输入法的定义
2、只有一个是激活的;
3、输入法同一时 间只能服务一个程序。
IMMS(InputMethodManagerService)
负责显示输入法,接收用户事件。
输入法内部逻辑,键盘布局,选词等,最终把选出的字符通过commitText提交出来。
由UI控件(View,TextView,EditText等)调用,用来操作输入法。比如,打开,关闭,切换输入法等。
下面说一下InputMethodManagerService这个控制中心是怎么样与三个模块交互的。
1、与WindowManagerSerivce的交互。
首先,InputMethodManagerService在初始化时,会调用IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE)),得到IWindowManager这个代理,然后通过IWindowManager与WindowManagerService交互。比如下面这些操作:
调用mIWindowManager.addWindowToken(mCurToken, WindowManager.LayoutParams.TYPE_INPUT_METHOD),让WindowManagerService显示输入法界面。
调用mIWindowManager.removeWindowToken(mCurToken)让输入法界面关闭。
调用mIWindowManager.inputMethodClientHasFocus(client)判断输入法是否聚焦。
2、与InputMethodService的交互。
InputMethodManagerService在内部维护着一个ArrayList<InputMethodInfo> mMethodList。这个列表会在服务启动时通过PackageManager查询当前系统中的输入法程序来得到。与之对应的,每一个输入法程序的AndroidManifest.xml中都会有一个Service,而每个Service中都会有标记来告诉系统,自己是个输入法程序。下面这个是从系统自带的例子Samples/SoftKeyboard/AndroidManifest.xml中的取出来的:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.softkeyboard">
<application android:label="@string/ime_name">
<service android:name="SoftKeyboard"
android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod" />
</intent-filter>
<meta-data android:name="android.view.im" android:resource="@xml/method" />
</service>
</application>
</manifest>
另外,InputMethodManagerService内部还有一个PackageReceiver,当系统中有程序的安装、删除、重启等事件发生时,会更新mMethodList。InputMethodManagerService打开,关闭,切换输入法时,其实就是在操作mMethodList中某个InputMethodInfo。把InputMethodInfo中的代表某个输入法的InputMethodService启动或者销毁,就实现了输入法的打开和关闭。
3、与InputMethodManager的交互
InputMethodManager中会包含一个IInputMethodManager,这个东西就是InputMethodManagerService的代理,打开关闭输入法这些操作就是由InputMethodManager中的某些方法调用IInputMethodManager中相应的方法来实现的。比如:
mService.getInputMethodList()获取输入法列表。
mService.updateStatusIcon(imeToken, packageName, iconId)更新输入法图标,即屏幕上方状态栏中的输入法图标。
mService.finishInput(mClient)隐藏当前输入法。这所以不说关闭输入法,是因为输入法服务启动起来以后,只有在系统关闭或者切换输入法时才会关闭。
mService.showSoftInput(mClient, flags, resultReceiver)打开当前输入法。
IMF简介
2、同时,当程序的某个需要输入法的view比如EditorView获得焦点时就会通过InputMethodManager向InputMethodManagerService请求显示输入法;
3、这时InputMethodManagerService收到请求后,会将请求的EditText的数据通信接口发送给当前输入法,并请求显输入法。输入法收到请求后,就显示自己的UI dialog,同时保存目标view的数据结构,当用户实现输入后,直接通过view的数据通信接口将字符传递到对应的View。
InputMethodManager
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
}
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
//这个进程的InputMethodManager实例就生成了
InputMethodManager imm = InputMethodManager.getInstance();
IWindowManager windowManager = getWindowManagerService();
} catch (RemoteException e) {
Log.e(TAG, "Failed to open window session", e);
}
}
return sWindowSession;
}
}
public static InputMethodManager getInstance() {
synchronized (InputMethodManager.class) {
if (sInstance == null) {
// InputMethodManager其实就是一个Binder service的proxy
IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
sInstance = new InputMethodManager(service, Looper.getMainLooper());
}
return sInstance;
}
}
InputMethodService
1、主要实现的功能
包括输入法内部逻辑,键盘布局,选词等,最终把选出的字符通过commitText提交出来。实现输入法的基础就是名为InputMethodService的类,比如要实现一个谷歌输入法,就是要extends本类。2、如何实现
onInitializeInterface() 顾名思义,它在初始化界面的时候被调用,而一般是由于配置文件的更改导致该函数的执行
onBinndInput() 它在另外的客户端和该输入法连接时调用
onStartInput() 非常重要的一个回调,它在编辑框中用户已经开始输入的时候调用。比如,当点击一个输入框,我们需要根据这个输入框的信息,设置输入法的一些特性。
onCreateInputView() 返回一个层次性的输入视图,而且只是在这个视图第一次显示的时候被调用
onCreateCandidatesView() 同onCreateInputView(),只不过创建的是候选框的视图。
onCreateExtractTextView() 比较特殊,是在全屏模式下的一个视图。
onStartInputView() 在输入视图被显示并且在一个新的输入框中输入已经开始的时候调用。