Android列表中EditText按回车按键后出现 focus search returned a view that wasn‘t able to take focus!崩溃异常解决

Android列表中EditText按回车按键后出现 focus search returned a view that wasn’t able to take focus!崩溃异常分析解决

一、前言

Android系统有个bug:List或者RecyclerView列表中如果存在多个不同类型的Item,其中有Editext,如果在Edittext点击输入法对话框总的完成会出现崩溃。

虽然这种情况,比如少见,但是还是记录一下。

解决这个问题有几种方法,一个是输入法里面适配,一个是系统代码不抛出异常,还有一个就是应用里面规避这个报错。

二、分析解决

1、分析报错日志

[15:27:48.364]logcat | grep AndroidRuntime
[15:27:48.631]09-06 15:27:23.979  1109  1109 D AndroidRuntime: Shutting down VM
[15:27:48.642]09-06 15:27:23.980  1109  1109 E AndroidRuntime: FATAL EXCEPTION: main
[15:27:48.645]09-06 15:27:23.980  1109  1109 E AndroidRuntime: Process: com.skg.settings, PID: 1109
[15:27:48.655]09-06 15:27:23.980  1109  1109 E AndroidRuntime: java.lang.IllegalStateException: focus search returned a view that wasn't able to take focus!
[15:27:48.664]09-06 15:27:23.980  1109  1109 E AndroidRuntime:        at android.widget.TextView.onKeyUp(TextView.java:9646)
[15:27:48.675]09-06 15:27:23.980  1109  1109 E AndroidRuntime:        at android.view.KeyEvent.dispatch(KeyEvent.java:2962)
[15:27:48.686]09-06 15:27:23.980  1109  1109 E AndroidRuntime:        at android.view.View.dispatchKeyEvent(View.java:15591)
[15:27:48.698]09-06 15:27:23.980  1109  1109 E AndroidRuntime:        at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1968)

报错说的是焦点异常。
不清楚是系统故意这样的还是系统的bug!

报错的代码就在TextView.java里面
framework\base\core\java\android\widget\TextView.java

            case KeyEvent.KEYCODE_NUMPAD_ENTER:
                if (event.hasNoModifiers()) {
  
                    if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0
                            || shouldAdvanceFocusOnEnter()) {
  
                        if (!hasOnClickListeners()) {
                            View v = focusSearch(FOCUS_DOWN);

                            if (v != null) {
                                if (!v.requestFocus(FOCUS_DOWN)) {
                                    throw new IllegalStateException("focus search returned a view "
                                            + "that wasn't able to take focus!");
                                }

这里看到是Enter回车后,一些判断后抛出了异常。

这里不做具体分析。有兴趣的自己看看。

2、解决

(1)设置imeOptions属性

在EditText属性里设置 android:imeOptions=“actionUnspecified” . imeOptions就是控制回车键具体作用的属性

<EditText
        android:id="@+id/title_content"
        android:layout_width="0dp"
        android:layout_height="60dp"
        android:hint="请输入标题"
        android:singleLine="true"
        android:maxLength="20"
        android:inputType="text"
        android:imeOptions="actionUnspecified"
        app:layout_constraintTop_toBottomOf="@id/cover_barrier"
        app:layout_constraintLeft_toRightOf="@id/title"
        app:layout_constraintRight_toRightOf="parent"/>

如果actionUnspecified属性设置后依然会报错,你可以尝试另外一个属性actionNone

(2)代码中设置监听事件

这种办法就是监听编辑器操作,然后将回车操作写成自己需要的功能.

            mEditView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
                @Override
                public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                    return true;
                }
            });

注意需要返回 true 表示你已经处理过这个事件了.

其实还有其他规避方法,有兴趣自己看看后面那个 庖丁解BUG 过程。

如果想验证测试一下,可以试试下面这段列表代码:

3、一段示例代码

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        RecyclerView rv = new RecyclerView(this);
        LinearLayoutManager lm = new LinearLayoutManager(this);
        rv.setLayoutManager(lm);
        rv.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        DividerItemDecoration did = new DividerItemDecoration(this, lm.getOrientation());
        rv.addItemDecoration(did);

        ArrayList<Integer> data = new ArrayList<Integer>(10);
        for (int i = 0; i < 13; i++) {
            data.add(i);
        }

        rv.setAdapter(new MyAdapter(data));

        setContentView(rv);
    }


    class MyAdapter extends RecyclerView.Adapter {
        ArrayList<Integer> data;
        int viewTypeTextView, viewTypeEditText, viewTypeCheckbox;

        public MyAdapter(ArrayList<Integer> data) {
            this.data = data;
            viewTypeEditText = this.data.size() - 2;
            viewTypeCheckbox = this.data.size() - 1;
        }

        @Override
        public int getItemViewType(int position) {
            if (position == data.size() - 2) {
                return viewTypeEditText;

            } else if (position == data.size() - 1) {
                return viewTypeCheckbox;

            } else {
                return viewTypeTextView;
            }
        }

        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {

            View view;

            if (viewType == viewTypeEditText) {
                view = buildEditText(viewGroup.getContext());

            } else if (viewTypeCheckbox == viewType) {
                view = buildCheckbox(viewGroup.getContext());

            } else {
                view = buildTextView(viewGroup.getContext());
            }

            return new MyHolder(view);
        }

        @Override
        public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder viewHolder, int position) {
        }

        @Override
        public int getItemCount() {
            return data.size();
        }

        private View buildTextView(Context context) {
            TextView textView = new TextView(context);
            textView.setText("文本项");
            textView.setTextSize(20);
            textView.setGravity(Gravity.CENTER);
            textView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            textView.setPadding(0, 50, 0, 50);

            return textView;
        }

        private View buildEditText(Context context) {
            EditText editText = new EditText(context);
            editText.setHint("输入框");
            editText.setInputType(EditorInfo.TYPE_CLASS_NUMBER);
            editText.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));

            return editText;
        }

        private View buildCheckbox(Context context) {
            CheckBox checkBox = new CheckBox(context);
            checkBox.setText("单选框");
            return checkBox;
        }

        class MyHolder extends RecyclerView.ViewHolder {
            public MyHolder(@NonNull View itemView) {
                super(itemView);
            }
        }
    }
}

在Edittext 中点击完成就会报错。

三、其他

其他博客的介绍:
Android开发 EditText按回车按键后出现 focus search returned a view that wasn’t able to take focus! 错误…

第一个:言简意赅,直接说明解决方案:
https://blog.csdn.net/weixin_30950237/article/details/102108266

第二个:庖丁解BUG:focus search returned a view that wasn’t able to take focus!
从根源上分析解决这个bug。
https://www.jianshu.com/p/9d107363cd68

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

峥嵘life

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值