Play商店预发布报告中的Android应用程序崩溃但在真实设备中工作
Posted
技术标签:
【中文标题】Play商店预发布报告中的Android应用程序崩溃但在真实设备中工作【英文标题】:Android app crash in play store prelaunch report but working in real device 【发布时间】:2019-07-13 17:18:48 【问题描述】:无法跟踪项目中的崩溃,我在 Play 商店预发布部分收到此错误,它显示在点击 EditText
时,它收到了错误。但在真实设备上没有崩溃。
问题:java.lang.IndexOutOfBoundsException:setSpan (4 ... 4) 结束长度超过 0
Fatal Exception: java.lang.IndexOutOfBoundsException: setSpan (4 ... 4) ends beyond length 0
at android.text.SpannableStringBuilder.checkRange(SpannableStringBuilder.java:1096)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:671)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:664)
at android.text.Selection.setSelection(Selection.java:76)
at android.text.Selection.setSelection(Selection.java:87)
at android.widget.EditText.setSelection(EditText.java:98)
at android.widget.EditText.performAccessibilityActionInternal(EditText.java:138)
at android.view.View.performAccessibilityAction(View.java:8892)
at android.view.AccessibilityInteractionController.performAccessibilityActionUiThread(AccessibilityInteractionController.java:668)
at android.view.AccessibilityInteractionController.-wrap6(AccessibilityInteractionController.java)
at android.view.AccessibilityInteractionController$PrivateHandler.handleMessage(AccessibilityInteractionController.java:1194)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5459)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
【问题讨论】:
*setSpan (4 ... 4) ends beyond length 0 在调用 setSpan 方法之前检查文本长度。 我没有使用setSpan方法,只使用edittext的方法是""" editText.isFocused(); editText.requestFocus(); editText.setText(""); """ 我的一个应用程序中确实存在这个问题,已经好几个月了。仅显示在发布前报告中,从不显示在生产中。而且我也不使用 setSpan。 这里也一样。对我来说,这也是由performAccessibilityAction
引起的。对我来说,这看起来像是 SDK 中的错误
我看到了完全相同的问题,只是它发生在运行 Android 6.0.1 的(真正的)根设备上。它从未被修复过。
【参考方案1】:
我在发布前报告和 FireBase 测试实验室中都看到了他的相同错误。我花了几个小时研究这个问题,我确信这是一个只影响 SDK
您可以使用以下代码复制相同的异常,确保字符串“1234”比您的 maxLength 长:
Bundle arguments = new Bundle();
arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "1234");
mEditText.performAccessibilityAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
那么,该怎么办呢?
一种选择是忽略它,因为它可能会影响一小部分用户。除非您认为您可能有许多用户使用辅助功能输入文本,并且他们也使用旧版 SDK (
另一种选择是将 build.gradle 中的 minSDKVersion 设置为 24。如果您有很多用户使用 SDK ,这可能会造成伤害
第三种选择是使用我想出的这个非常丑陋的解决方法:
if(Build.VERSION.SDK_INT <= 23)
ViewGroup rootView = findViewById(R.id.your_layout_that_contains_edittexts);
ArrayList<View> views = rootView.getTouchables();
for(View view : views)
if(view instanceof EditText)
EditText mEditText = (EditText)view;
mEditText.setAccessibilityDelegate(new View.AccessibilityDelegate()
@Override
public boolean performAccessibilityAction(View host, int action, Bundle arguments)
if (action == AccessibilityNodeInfo.ACTION_SET_TEXT)
//do something here to make sure index out of bounds does not occur
int maxLength = 0;
for(InputFilter filter : mEditText.getFilters())
if(filter instanceof InputFilter.LengthFilter)
maxLength = ((InputFilter.LengthFilter)filter).getMax();
Set<String> keys = arguments.keySet();
for(String key : keys)
if(arguments.get(key) instanceof CharSequence)
if(arguments.get(key) != null)
arguments.putCharSequence(key, ((CharSequence) arguments.get(key)).subSequence(0, maxLength));
mEditText.setText(arguments.getCharSequence(key));
return true;
);
好的,所以我确实说它很丑,但它确实有效。将 your_layout_that_contains_edittexts 替换为包含所有 EditText 的布局的 id。
基本上,如果 SDK
【讨论】:
+1 建议如何重现!为了将来参考,有时您甚至需要更长的字符串才能崩溃,因为“1234”可能不够长【参考方案2】:受@smitty1 的solution 启发,我做了这个。我在自定义 EditText 中处理它,而不是检查视图中的所有 EditText:
open class MaxLengthEditText : AppCompatAutoCompleteTextView
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
/*
* On Android API versions <= 23 the app crashes if a text that is longer than the max length of the EditText
* is set using an accessibility action. To avoid this we cut the text down to the maximum allowed length.
*/
override fun performAccessibilityAction(action: Int, arguments: Bundle?): Boolean
if (Build.VERSION.SDK_INT <= 23 && action == AccessibilityNodeInfo.ACTION_SET_TEXT)
filters.forEach filter ->
if (filter is InputFilter.LengthFilter)
val maxLength = filter.max
arguments?.keySet()?.forEach key ->
if (arguments[key] is CharSequence)
val shorterText =
arguments.getCharSequence(key)?.subSequence(0, maxLength)
setText(shorterText)
return true
return super.performAccessibilityAction(action, arguments)
【讨论】:
【参考方案3】:在我的情况下,EditText 没有设置maxLength
。但是我们使用了一些自定义的InputFilter
。如下所示:
private val textFilter = object : InputFilter
override fun filter(source: CharSequence, start: Int, end: Int, dest: Spanned, dstart: Int, dend: Int): CharSequence?
return when
good -> null // just allow change as is
bad -> "" // ignore change totally[*].
else -> magic // return a calculated value
问题[*] 通过返回空字符串完全忽略了该值,这导致 Marshmellow 及以下设备崩溃。这是我解决这个问题的方法:
private val textFilter = object : InputFilter
override fun filter(source: CharSequence, start: Int, end: Int, dest: Spanned, dstart: Int, dend: Int): CharSequence?
return when
good -> null // just allow change as is
bad -> (dest.toString() + source.subSequence(start, end)).subSequence(dstart, dstart + (end - start)) // ignore change totally[*].
else -> magic // return a calculated value
关键点是不返回任何小于更改(end-start)
(在M及以下设备上)。
我仍然感谢以前的答案,它们帮助我确定了根本原因。
【讨论】:
以上是关于Play商店预发布报告中的Android应用程序崩溃但在真实设备中工作的主要内容,如果未能解决你的问题,请参考以下文章
Android Play 商店中的 Delphi 11 应用程序显示警告:非 SDK API
如何仅针对已安装应用程序的用户在 Android Play 商店上发布应用程序?