InputMethodManager.java
InputMethodManager.java中定义一个变量: IInputMethodSession mCurMethod;
从表面上看,似乎是远程使用的。
我们在后面有这样一个变量:这个是传到InputMethodManagerService中回调使用的。
final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
public void onBindMethod(InputBindResult res) {
//这里发送一个消息:MSG_BIND
mH.sendMessage(mH.obtainMessage(MSG_BIND, res));
}
}
class H extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_BIND: {
//很明显:从InputMethodManagerService中传递过来的
final InputBindResult res = (InputBindResult)msg.obj;
mCurMethod = res.method;
}
break;
……
}
}
}
InputMethodManagerService.java
public boolean handleMessage(Message msg) {
……
//这里进行回调
case MSG_BIND_METHOD:
args = (HandlerCaller.SomeArgs)msg.obj;
try {
((IInputMethodClient)args.arg1).onBindMethod(
(InputBindResult)args.arg2);
}
}
那么,谁发送了这个消息:
void onSessionCreated(IInputMethod method, IInputMethodSession session) {
synchronized (mMethodMap) {
if (mCurMethod != null && method != null
&& mCurMethod.asBinder() == method.asBinder()) {
//mCurClient 代表是当前SoftInput的客户端
if (mCurClient != null) {
mCurClient.curSession = new SessionState(mCurClient,
method, session);
mCurClient.sessionRequested = false;
InputBindResult res = attachNewInputLocked(true);
if (res.method != null) {
executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
MSG_BIND_METHOD, mCurClient.client, res));
}
}
}
}
}
mCurClient与curSession 详见:输入法中相关class.doc
那么,谁调用这个onSessionCreated将method和session传进来的呢?继续向下:
又是一个远程的方法实现中,调用上面这个方法,strange!!!
private static class MethodCallback extends IInputMethodCallback.Stub {
……
public void sessionCreated(IInputMethodSession session) throws RemoteException {
mParentIMMS.onSessionCreated(mMethod, session);
}
}
没办法,只有继续向下跟踪:这个远程方法给谁用的???
这个方法有两处进行调用:startInputUncheckedLocked和serviceConnection时调用:具体都是如下:
executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
MSG_CREATE_SESSION, mCurMethod,
new MethodCallback(mCurMethod, this)));
又是通过发送消息MSG_CREATE_SESSION之后才正式回调MethodCallback中的sessionCreated。
最终又绕回去了,还是需要知道IInputMethod mCurMethod这个变量是如何初始化的。
我们看到在InputMethodManagerService重载的函数中有如下调用:
public void onServiceConnected(ComponentName name, IBinder service) {
……
if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
mCurMethod = IInputMethod.Stub.asInterface(service);
}
}
是不是仍然一头雾水?但是不觉得有黎明破晓的激动吗?
我们知道:
public abstract class AbstractInputMethodService extends Service {
……
final public IBinder onBind(Intent intent) {
if (mInputMethod == null) {
//这里创建了InputMethod接口的方法
mInputMethod = onCreateInputMethodInterface();
}
//这里创建一个IInputMethodWrapper
return new IInputMethodWrapper(this, mInputMethod);
}
}
它本质上是一个service,但是它是一个抽象类,它的实现必然是由其子类实现的。
public class InputMethodService extends AbstractInputMethodService {
}
我们回到,InputMethodManagerService中,在建立service时才将service中的回调方法IInputMethod加载进来,这似乎风马牛不相及,慢着:
由IInputMethodWrapper 声明可以看出玄机:
class IInputMethodWrapper extends IInputMethod.Stub {
}
现在,我们可以确定,InputMethodManagerService中的mCurMethod是由InputMethodService实现并传过来的。虽然,InputMethodService也是继承来的。
回到原来的问题:谁发送MSG_CREATE_SESSION的Message
有两个位置会发送:
startInputUncheckedLocked
和onServiceConnected
先分析startInputUncheckedLocked这个函数:
InputBindResult startInputUncheckedLocked(ClientState cs,
IInputContext inputContext, EditorInfo attribute, int controlFlags) {
//没有选中任何输入法,返回
if (mCurMethodId == null) {
return mNoBinding;
}
//输入法需要切换了
if (mCurClient != cs) {
//将当前的Client输入法解除绑定
unbindCurrentClientLocked();
}
//如果屏幕是亮着的
if (mScreenOn) {
try {
//将需要切换的输入法设置为活动的
cs.client.setActive(mScreenOn);
} catch (RemoteException e) {
}
}
//我们开启一个输入法,在数据库中会记录这个输入法的名称,mCurId 是从数据库中读取的名称
if (mCurId != null && mCurId.equals(mCurMethodId)) {
if (cs.curSession != null) {
//将当前的client端和InputMethodService绑定,并返回包含id、IInputMethodSession等信//息的InputBindResult
return attachNewInputLocked(
(controlFlags&InputMethodManager.CONTROL_START_INITIAL) != 0);
}
//若是已经绑定
if (mHaveConnection) {
if (mCurMethod != null) {
if (!cs.sessionRequested) {
cs.sessionRequested = true;
//发送创建 MSG_CREATE_SESSION 消息
executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
MSG_CREATE_SESSION, mCurMethod,
new MethodCallback(mCurMethod, this)));
}
return new InputBindResult(null, mCurId, mCurSeq);
}
}
return startInputInnerLocked();
}
我们到handleMessage中看看如何创建Session的
case MSG_CREATE_SESSION:
args = (HandlerCaller.SomeArgs)msg.obj;
try {
//这里将MethodCallback的实例传到IInputMethodWrapper中去了
((IInputMethod)args.arg1).createSession(
(IInputMethodCallback)args.arg2);
} catch (RemoteException e) {
}
return true;
然后调用InputMethodWrapper中的createSession来创建Session
IInputMethodWrapper.java
public void createSession(IInputMethodCallback callback) {
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_CREATE_SESSION, callback));
}
public void executeMessage(Message msg) {
case DO_CREATE_SESSION: {
//msg.obj是MethodCallback的实例
inputMethod.createSession(new InputMethodSessionCallbackWrapper(
mCaller.mContext, (IInputMethodCallback)msg.obj));
return;
}
}
我们知道,InputMethodService继承自AbstractInputMethodService,但是忽略了这个父类中所用到的类:
public abstract class AbstractInputMethodImpl implements InputMethod {
public void createSession(SessionCallback callback) {
//开始调用MethodCallbacks中中的sessionCreated了,那么,传入参数是什么呢?
callback.sessionCreated(onCreateInputMethodSessionInterface());
}
}
它实现了我们需要的方法:createSession
继续向下:
InputMethodService.java
//这里InputMethodSessionImpl才是真正的InputMethodService的回调方法类
public AbstractInputMethodImpl onCreateInputMethodInterface() {
return new InputMethodSessionImpl();
}
//这里实现InputMethodSession中定义的接口如下所示
public class InputMethodSessionImpl extends AbstractInputMethodSessionImpl {
public void finishInput() {}
public void viewClicked(boolean focusChanged) {}
……
}
AbstractInputMethodSessionImpl 实现了InputMethodSession的方法,这就是说IInputMethodSession的实现就是在这里的InputMethodSessionImpl。
我们现在总结一下:
InputMethodManager 通过 InputMethodManagerService的本地代理访问InputMethodManagerService
InputMethodManager 通过 IInputMethodSession访问InputMethodService
InputMethodManagerService通过 IInputMethodClient 回调InputMethodManager