接收输入法被切换的广播

输入法被切走时是否收到通知?被切走输入法是否还在运行?

广播ACTION_INPUT_METHOD_CHANGED

在Android Developers ACTION_INPUT_METHOD_CHANGED中说:
Broadcast Action: An input method has been changed.
如果输入法由A切到B,A应该能收到该广播,如果再由B切到C,还能收到吗?
我在AndroidIMESample中拉出分支验证此问题。

创建IMChangedReceiver来处理该广播:创建Receiver添加onReceiver()函数:

1
2
3
4
5
6
7
8
9
10
public class IMChangedReceiver extends BroadcastReceiver {
public IMChangedReceiver(){

}

@Override
public void onReceive(Context context, Intent intent){
Toast.makeText(context, "接收到IMChanged广播", Toast.LENGTH_SHORT).show();
}
}

静态注册广播

AndroidManifest.xml中添加如下行:

1
2
3
4
5
6
7
8
9
10
11
12
    ...
<application>
...
<service> ... </service>

<receiver android:name=".IMChangedReceiver">
<intent-filter>
<action android:name="android.intent.action.INPUT_METHOD_CHANGED"/>
</intent-filter>
</receiver>
</application>
</manifest>

执行Build > Build APK > Reveal in Finder,把apk拖到模拟器里完成安装。实验结果是:

  1. SGDXAndroidIMESample切到别的输入法时,SGDXAndroidIMESample能收到广播。
  2. Android键盘(AOSP)切到Sample Soft Keyboard时,SGDXAndroidIMESample也能收到广播。也就是说不管切换和被切换的输入法和SGDXAndroidIMESample有没有关系,它都能收到切换的广播。
  3. 重启机器,无需先切出SGDXAndroidIMESample,依然是:不管切换和被切换的输入法和SGDXAndroidIMESample有没有关系,它都能收到切换的广播。

代码详见这里

动态注册广播

删除AndroidManifest.xml中静态注册receiver的代码,在AndroidIMESampleService中添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

public class AndroidIMESampleService extends InputMethodService
implements KeyboardView.OnKeyboardActionListener {
...
private IMChangedReceiver mIMChangedReceiver = new IMChangedReceiver(); // 声明广播接收器

@Override
public View onCreateInputView() {
...

// 动态注册IMChanged广播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_INPUT_METHOD_CHANGED);
registerReceiver(mIMChangedReceiver, intentFilter);

return mKeyboardView;
}

安装完成,尝试切换,实验结果是:

  1. 仅从SGDXAndroidIMESample切到别的输入法时,SGDXAndroidIMESample才能收到广播,其它的切换均收不到。
  2. 重启机器,依然是:仅从SGDXAndroidIMESample切到别的输入法时,SGDXAndroidIMESample才能收到广播,其它的切换均收不到。

代码详见这里

分析

也就是说如果是静态注册,只要不是被切入,输入法总能收到切换的广播;如果是动态注册,输入法仅能收到被切出的广播。
问题:输入法被切走以后进程还在吗?重启后如果不切入输入法,进程还在吗?如果在,为什么收不到动态注册的广播?如果不在,又是怎么收到静态注册广播的呢?

可以通过命令adb shell ps来查看进程。

  • 当输入法被设为默认
    重启手机后,输入法进程就会被启动,并且Service的onStartInput()函数也会被调用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $ adb shell ps
    USER PID PPID VSZ RSS WCHAN ADDR S NAME
    ...
    u0_a84 2185 1393 1426324 65160 SyS_epoll_wait 0 S com.palanceli.ime.androidimesample
    ...

    $ adb logcat|grep "palanceli"
    07-18 15:30:39.426 1495 1706 I ActivityManager: Start proc 2172:com.palanceli.ime.androidimesample/u0a84 for service com.palanceli.ime.androidimesample/.AndroidIMESampleService
    07-18 15:30:40.250 2172 2172 D class com.palanceli.ime.androidimesample.AndroidIMESampleService: onStartInput:
    07-18 15:30:40.637 2172 2172 D class com.palanceli.ime.androidimesample.AndroidIMESampleService: onStartInput:
  • 当输入法为非默认
    重启手机后,输入法进程不会被启动,除非手动调起键盘。

如果是静态注册的BroadCastReceiver,即使进程没有启动,当广播发生时,系统会启动进程再把广播发送给它,这与输入法是否默认无关,而是静态注册BroadCastReceiver的性质。这在广播机制学习笔记(二)的源码分析中也能找到。
如果是动态注册的BroadCastReceiver,则进程必须是启动的才能收到广播。在Android源码的Activity或Service等组件被销毁时,应该能找到清理广播接收器的代码[待查]。