android4.0 输入法框架分析

来源:互联网 发布:与制造业相关的数据 编辑:程序博客网 时间:2024/04/29 16:50

InputMethodManager.java

InputMethodManager.java中定义一个变量:  IInputMethodSession mCurMethod;

从表面上看,似乎是远程使用的。

我们在后面有这样一个变量mClient :这个是传到InputMethodManagerService中回调使用的:

主要在startInputInner或者onWindowFocus中调用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;

……

}

}

}

从上面可以知道,mClientInputMehtodManager中代表一个启动的Input的客户端,它在正常启动后传到InputMethodManagerService中使用。那么,InputMethodManager中的mCurMethod如何初始化的?

InputMethodManagerService.java

public boolean handleMessage(Message msg) {

……

//和谁bind的?

case MSG_BIND_METHOD:

args = (HandlerCaller.SomeArgs)msg.obj;

        try {

 //回调InputMethodManager中的IInputMethodClient中方法

             ((IInputMethodClient)args.arg1).onBindMethod(

                  (InputBindResult)args.arg2);

       }

break;

……

        case MSG_CREATE_SESSION:

        args = (HandlerCaller.SomeArgs)msg.obj;

        try {

            ((IInputMethod)args.arg1).createSession(

                            (IInputMethodCallback)args.arg2);

       } catch (RemoteException e) {

       }

       return true;

……

}

那么,谁发送了这个消息:

    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));

                    }

                }

            }

        }

    }

mCurClientcurSession 详见:输入法中相关class.doc

那么,谁调用这个onSessionCreatedmethodsession传进来的呢?继续向下:

又是一个远程的方法实现中,调用上面这个方法,strange!!!

private static class MethodCallback extends IInputMethodCallback.Stub {

……

public void sessionCreated(IInputMethodSession session) throws RemoteException {

       mParentIMMS.onSessionCreated(mMethod, session);

}

}

没办法,只有继续向下跟踪:这个远程方法给谁用的???

这个方法有两处进行调用:startInputUncheckedLockedserviceConnection时调用:具体都是如下:

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())) {

//这个service究竟传进来的是什么?

mCurMethod = IInputMethod.Stub.asInterface(service);

}

}

mCurIntent 定义如下:

IInputMethod mCurIntent;

是不是仍然一头雾水?但是不觉得有黎明破晓的激动吗?

我们知道:

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实现并传过来的IInputMethodWrapper的实例。虽然,InputMethodService也是继承来的。

回到原来的问题:idMSG_CREATE_SESSIONMessage在下面两个函数中发送:

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绑定,并返回包含idIInputMethodSession等信//息的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();

}

由上面知道:mCurMethod实际上是IInputMethodWrapper的实例,我们到handleMessage中看看如何创建Session的:

case MSG_CREATE_SESSION:

    args = (HandlerCaller.SomeArgs)msg.obj;

try {

//arg1mCurMethod

//arg2MethodCallback

//这里将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.objMethodCallback的实例

        inputMethod.createSession(new InputMethodSessionCallbackWrapper(

                        mCaller.mContext, (IInputMethodCallback)msg.obj));

        return;

}

}

inputMethodInputMethod类型的:它在AbstractInputMethodService中实现:

public abstract class AbstractInputMethodImpl implements InputMethod

我们知道,InputMethodService继承自AbstractInputMethodService,但是忽略了这个父类中所用到的类:

public abstract class AbstractInputMethodImpl implements InputMethod {

        public void createSession(SessionCallback callback) {

//开始调用InputMethodSessionCallbackWrapper中的sessionCreated了,那么,传入参数是什么呢?

            callback.sessionCreated(onCreateInputMethodSessionInterface());

        }

}

莫非onCreateInputMethodSessionInterfaceInputMethodSession 有关?

static class InputMethodSessionCallbackWrapper implements InputMethod.SessionCallback {

        InputMethodSessionCallbackWrapper(Context context, IInputMethodCallback cb) {

            mContext = context;

//这里将在InputMethodManagerService中创建的MethodCallback实例赋给mCb

            mCb = cb;

        }

public void sessionCreated(InputMethodSession session) {

            try {

                if (session != null) {

//IInputMethodSessionWrapper 继承自 IInputMethodSession.Stub,这要找的

                    IInputMethodSessionWrapper wrap =

                            new IInputMethodSessionWrapper(mContext, session);

//这里将IInputMethodSessionWrapper传回InputMethodManagerService

                    mCb.sessionCreated(wrap);

                } else {

                    mCb.sessionCreated(null);

                }

            } catch (RemoteException e) {

            }

}

}

IInputMethodSessionWrapper定义如下:

class IInputMethodSessionWrapper extends IInputMethodSession.Stub

这就是我们一直寻找的。

我们还有一个疑问:

IInputMethodSessionWrapper.java

在构造函数中:session是如何创建的呢?

继续向下:

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,它的远程方法是:IInputMethodSession 

我们现在总结一下:

InputMethodManager 通过 InputMethodManagerService的本地代理访问InputMethodManagerService

InputMethodManager  通过 IInputMethodSession访问InputMethodService

InputMethodManagerService通过 IInputMethodClient 回调InputMethodManager  

InputMethodManagerService 通过 IInputMethodWrapper(mCurMethod)  回调InputMethodService