源码分析软键盘弹出失效问题

本文深入探讨了软键盘在Android应用中偶尔无法弹出的问题。通过源码分析,揭示了焦点管理与软键盘显示之间的关系,提出了解决方案,并建议在View的onAttachedToWindow()方法中调用软键盘显示,确保其正确弹出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源码分析软键盘弹出失效问题

平常开发中,经常碰到 EditText 输入内容时需要调起软件盘。但是有时发现调用了之后没有生效,软键盘并没有弹出来。通常做法如下,延迟执行,虽然大概率提升了软键盘弹出的几率,但是偶尔还是会失效,没有从根本上解决问题的痛点。

editTextView.postDelayed(new Runnable() {
            @Override
            public void run() {
                InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                manager.showSoftInput(editTextView, 0);
            }
        },500);

下面我们就从源码着手来分析一下问题所在。InputMethodManager 管理者输入相关逻辑,自然就包括软键盘的显示与隐藏,我们从 showSoftInput() 方法作为入口来看。

InputMethodManager.java

	final IInputMethodManager mService;
	
    public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
        ......

            try {
                return mService.showSoftInput(mClient, flags, resultReceiver);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        ......
    }

这里会最终调用 InputMethodManagerServiceshowSoftInput() 方法。 InputMethodManagerServiceIInputMethodManager.Stub 的一个实现类

InputMethodManagerService.java

    @Override
    public boolean showSoftInput(IInputMethodClient client, int flags,
            ResultReceiver resultReceiver) {
        ......
        // We need to check if this is the current client with
        // focus in the window manager, to allow this call to
        // be made before input is started in it.
        //槟果~~~大致意思就是,这玩意在这里会检查一下当前 window 的焦点,
        //如果没有获取焦点的话,直接返回 false 就失效了 - -!
        if (!mIWindowManager.inputMethodClientHasFocus(client)) {
            return false;
        }
		 ......
        return showCurrentInputLocked(flags, resultReceiver);
    }

来,我们在看下这个 mIWindowManagerinputMethodClientHasFocus

WindowManagerService.java

    @Override
    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
        synchronized (mWindowMap) {
            // TODO: multi-display
            //通过默认的显示设备的焦点进行判断,因为开始流行牛逼的分屏了。。哈哈
            if (getDefaultDisplayContentLocked().inputMethodClientHasFocus(client)) {
                return true;
            }

            // Okay, how about this...  what is the current focus?
            // It seems in some cases we may not have moved the IM
            // target window, such as when it was in a pop-up window,
            // so let's also look at the current focus.  (An example:
            // go to Gmail, start searching so the keyboard goes up,
            // press home.  Sometimes the IME won't go down.)
            // Would be nice to fix this more correctly, but it's
            // way at the end of a release, and this should be good enough.
            // 这段话的大致意思就是 他们通过这个修复了一个系统的bug,
            // 进入 邮件app ,弹出软键盘,立即安 home 键返回,
            // 这个时候软键盘还在,不符合预期
            if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
                    && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
                return true;
            }
        }
        return false;
    }
    

到这里我们就大致明白为啥软键盘有时候没有弹出来呢,就是当前 window 没有获取到焦点,即当前 window 是否已经完全在当前屏幕上显示出来。

原理我们已经了解了,具体怎么解决呢。其实,不管在 Activity 中,或者在 View 中都有一个 onAttachedToWindow() 方法。所以,在这个方法中调起软键盘就可以正常显示了。

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        manager.showSoftInput(editTextView, 0);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值