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

时间:2019-02-20 05:06:31

标签: android android-edittext indexoutofboundsexception

无法跟踪项目中的崩溃,我在Play商店预启动部分中收到此错误,点击public static void main(String[] args) { final int SIZE = 95; // total # of ascii vals being used int[] availableChars = new int[SIZE]; int[] ePhrase = new int[SIZE]; int[] dePhrase = new int[SIZE]; for(int i = 0; i < SIZE; i++){ availableChars[i] = (i + 32); } for(int i = 0; i < SIZE; i++){ ePhrase[i] = encrypt(availableChars[i] - 32); } for(int i = 0; i < SIZE; i++){ dePhrase[i] = decrypt(ePhrase[i] - 32); } System.out.print("\n"); for(int i = 0; i < SIZE; i++){ System.out.print(i + " "); } System.out.print("\n"); for(int i = 0; i < SIZE; i++){ System.out.print((char)availableChars[i] + " "); if(i >= 10){ System.out.print(" "); } } System.out.print("\n"); for(int i = 0; i < SIZE; i++){ System.out.print((char)ePhrase[i] + " "); if(i >= 10){ System.out.print(" "); } } System.out.print("\n"); for(int i = 0; i < SIZE; i++){ System.out.print((char)dePhrase[i] + " "); if(i >= 10){ System.out.print(" "); } } } public static int encrypt(int val){ return ((val + 9) % 94) + 32; } public static int decrypt(int val){ return ((val - 9) % 94) + 32; } 时显示此错误,并得到了错误。但在真实设备上没有崩溃。

问题:java.lang.IndexOutOfBoundsException:setSpan(4 ... 4)结束于长度0之外

EditText

3 个答案:

答案 0 :(得分:6)

受@ 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)
    }
}

答案 1 :(得分:0)

在发布前的报告和FireBase测试实验室中,我都看到了他的相同错误。我花了几个小时研究此问题,并且确定这是一个仅会影响SDK <= 23的错误,并由AccessibilityNodeInfo#performAction(ACTION_SET_TEXT)触发。 看来此方法完全忽略了maxLength属性,该属性继而导致IndexOutOfBoundsException。

您可以使用以下代码复制相同的异常,并确保字符串“ 1234”长于您的maxLength:

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

那么,该怎么办?

一个选择是忽略它,因为它可能会影响很小一部分用户。除非您认为您可能有许多用户使用辅助功能来输入文本,并且他们还使用较旧的SDK(<= 23)。

另一种选择是将build.gradle中的minSDKVersion设置为24。如果您有很多使用SDK <= 23

的用户,则可能会受到伤害

第三个选择是使用我想出的这个非常丑陋的解决方法:

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 <= 23,它将循环遍历ViewGroup中的所有EditText,并通过AccessibilityDelegate覆盖performAccessibilityAction,并确保输入的文本不会超过EditText的maxLength值。

答案 2 :(得分:0)

在我的情况下,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及以下设备上)的任何内容。


我仍然感谢以前的回答,这些问题可以帮助我确定根本原因。