简体   繁体   English

Play 商店预发布报告中的 Android 应用程序崩溃,但可在真实设备中运行

[英]Android app crash in play store prelaunch report but working in real device

Not able to track crash in the project, I got this error in play store pre-launch section, it showing on click of EditText , it got the error.无法跟踪项目中的崩溃,我在 Play 商店预启动部分收到此错误,它在单击EditText ,它收到错误。 but not getting any crash on a real device.但在真实设备上没有发生任何崩溃。

Issue: java.lang.IndexOutOfBoundsException: setSpan (4 ... 4) ends beyond length 0问题: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)

I was seeing his same error, both in the pre-launch report and in FireBase test lab.我在发布前报告和 FireBase 测试实验室中都看到了他同样的错误。 I spent several hours looking into this and I am sure it is a bug that only affects SDK <= 23 and is triggered by AccessibilityNodeInfo#performAction(ACTION_SET_TEXT).我花了几个小时研究这个问题,我确定这是一个只影响 SDK <= 23 的错误,并且由 AccessibilityNodeInfo#performAction(ACTION_SET_TEXT) 触发。 It seems this method completely ignores the maxLength attribute which in turn causes the IndexOutOfBoundsException.这个方法似乎完全忽略了 maxLength 属性,这反过来又导致了 IndexOutOfBoundsException。

You can duplicate this same exception with the following code, making sure the string "1234" is longer than your maxLength:您可以使用以下代码复制相同的异常,确保字符串“1234”比您的 maxLength 长:

 Bundle arguments = new Bundle();
 arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "1234");
 mEditText.performAccessibilityAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);

So, what to do about it?那么,该怎么办呢?

One option is to just ignore it as it is likely to affect a very small subset of users.一种选择是忽略它,因为它可能会影响非常小的用户子集。 that is unless you think you might have many users using accessibility functions to enter text and they are also using older SDKs (<= 23).除非您认为可能有许多用户使用辅助功能来输入文本,并且他们也在使用较旧的 SDK (<= 23)。

Another option would be to set your minSDKVersion in your build.gradle to 24. This might hurt if you have a lot of users using SDK <= 23另一种选择是将 build.gradle 中的 minSDKVersion 设置为 24。如果您有很多用户使用 SDK <= 23,这可能会造成伤害

A third option would be to use this very ugly workaround I came up with:第三种选择是使用我想出的这个非常丑陋的解决方法:

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;
                    }
                });

            }
        }

    }

OK, so I did say it was ugly, but it does work.好的,所以我确实说它很丑,但它确实有效。 Replace your_layout_that_contains_edittexts with the id of a layout that contains all your EditTexts.将 your_layout_that_contains_edittexts 替换为包含所有 EditText 的布局的 id。

Basically, if SDK <= 23, it cycles through all the EditTexts in the ViewGroup and for each one, overrides the performAccessibilityAction via AccessibilityDelegate and ensures that the text being entered never exceeds the EditText's maxLength value.基本上,如果 SDK <= 23,它会循环遍历 ViewGroup 中的所有 EditText,对于每个 EditText,通过 AccessibilityDelegate 覆盖 performAccessibilityAction 并确保输入的文本永远不会超过 EditText 的 maxLength 值。

Inspired by @smitty1's solution I made this one.受到@smitty1解决方案的启发,我做了这个。 I handle it in a custom EditText instead of checking all EditTexts in a view:我在自定义 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)
    }
}

In my case EditText did not have a maxLength set.在我的情况下 EditText 没有设置maxLength However we are using some custom InputFilter .但是我们正在使用一些自定义InputFilter Here how it looks like:这是它的样子:

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
        }
    }
}

Problem[*] was ignoring the value totally by returning empty String which was causing crash on Marshmellow and below devices.问题 [*] 通过返回导致 Marshmellow 及以下设备崩溃的空字符串完全忽略了该值。 Here is how I have solved this:这是我解决这个问题的方法:

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
        }
    }
}

Key Point is not to return anything smaller than the change (end-start) (on M and below devices) .关键点是不要返回任何小于更改(end-start) (在 M 及以下设备上) 的东西


I still thank previous answers which helped me to identify the root cause.我仍然感谢以前的答案,它们帮助我确定了根本原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Google Play 预发布报告崩溃 - Google Play Prelaunch Report Crash 我是否应该相信Google应用崩溃报告,因为同样的事情在真实设备中也能正常工作 - Should I believe in google app crash report because same things are working in real device Play 商店崩溃报告 - Room + AsyncTask 中的 IllegalStateException 但仅适用于 Android 10 - Play Store crash report - IllegalStateException in Room + AsyncTask but only on Android 10 Android应用程序可在模拟器上运行,但不能在真实设备上运行,SharePreferences - Android app working on emulator but not real device, SharePreferences Android 应用程序在真实设备上崩溃但在模拟器上工作 - Android app crashing on real device but working on emulator React Native 应用程序 - 在 Android 8 真实设备上启动时崩溃/关闭 - React Native app - crash/close on startup on Android 8 real device 我的TTS应用程序无法在实际的Android设备中运行 - My tts app is not working in real android device Android应用程序在模拟器上工作,但不在真实设备上 - Android app working on emulator but not on real device 使用 Android Studio Android 应用程序在设备上运行 Google plus 但从 Play 商店下载时不起作用 - Using Android Studio Android app Working Google plus on device but when downloaded from play store Not Work Android应用崩溃报告 - Android app crash report
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM