Rav*_*dav 18 android android-edittext indexoutofboundsexception
无法跟踪项目中的崩溃,我在 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)
Run Code Online (Sandbox Code Playgroud)
smi*_*ty1 13
我在发布前报告和 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);
Run Code Online (Sandbox Code Playgroud)
那么,该怎么办呢?
一种选择是忽略它,因为它可能会影响非常小的用户子集。除非您认为您可能有许多用户使用辅助功能来输入文本,并且他们也在使用较旧的 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;
}
});
}
}
}
Run Code Online (Sandbox Code Playgroud)
好的,所以我确实说它很丑,但它确实有效。将 your_layout_that_contains_edittexts 替换为包含所有 EditText 的布局的 id。
基本上,如果 SDK <= 23,它会循环遍历 ViewGroup 中的所有 EditText,对于每个 EditText,通过 AccessibilityDelegate 覆盖 performAccessibilityAction 并确保输入的文本永远不会超过 EditText 的 maxLength 值。
受到@smitty1解决方案的启发,我做了这个。我在自定义 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)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1432 次 |
| 最近记录: |