focus search returned a view that wasn't able to take focus!【已更新】

博客详细分析了一个在Android开发中遇到的偶发崩溃问题,日志显示'focus search returned a view that wasn't able to take focus!'。问题出现在RecyclerView列表中,包含TextView、EditText和CheckBox的Item。当点击EditText后直接点击回车,系统尝试焦点转移时引发崩溃。通过复现路径、源码分析和调试,发现原因是CheckBox在TouchMode下无法获取焦点。解决方案包括设置EditText的OnClickListener、使CheckBox在TouchMode下可聚焦、调整imeOptions和添加OnEditorActionListener。
摘要由CSDN通过智能技术生成

问题表现

在开发中遇到一个偶现的崩溃,日志堆栈如下:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.edittextdemo, PID: 9528
    java.lang.IllegalStateException: focus search returned a view that wasn't able to take focus!
        at android.widget.TextView.onKeyUp(TextView.java:7591)
        at android.view.KeyEvent.dispatch(KeyEvent.java:2788)
        at android.view.View.dispatchKeyEvent(View.java:11780)
        at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1845)
        at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1845)
        at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1845)
        at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1845)
        at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1845)
        at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1845)
        at com.android.internal.policy.DecorView.superDispatchKeyEvent(DecorView.java:547)
        at com.android.internal.policy.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1884)
        at android.app.Activity.dispatchKeyEvent(Activity.java:3430)
        at android.support.v7.app.AppCompatActivity.dispatchKeyEvent(AppCompatActivity.java:534)
        at android.support.v7.view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrapper.java:58)
        at android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.dispatchKeyEvent(AppCompatDelegateImplBase.java:316)
        at com.android.internal.policy.DecorView.dispatchKeyEvent(DecorView.java:421)
        at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:5371)
        at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5243)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4737)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4790)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4756)
        at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4887)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4764)
        at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4944)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4737)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4790)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4756)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4764)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4737)
        at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7363)
        at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7337)
        at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7295)
        at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:4315)
        at android.os.Handler.dispatchMessage(Handler.java:109)
        at android.os.Looper.loop(Looper.java:166)
        at android.app.ActivityThread.main(ActivityThread.java:7555)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:469)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:963)

复现路径

解决任何缺陷,不仅仅是崩溃问题,解决问题的第一步都是找到复现路径。如果找到了稳定复现的路径,那么恭喜你:已经成功了一半了!

对于本文中的崩溃问题,经过一层一层的抽丝剥茧,逐步剔除无关代码,终于在 Demo 工程中找到了稳定复现的路径。

Demo 工程是个列表页,用 RecyclerView 实现,列表中有 3 种类型的 Item:TextView、仅支持数字类型输入的 EditText 和 CheckBox。

当点击输入框后直接点击软键盘的回车按钮,必崩。完整代码和效果录屏分别如下:

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 = buildTextV
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值