Android4.0 输入法框架分析

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 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/pxgfw.html