Android Edittext如何将信息传递给输入法inputmethod的流程

问题描述:在message输入信息的时候,会弹框进入到全屏输入法界面,这时候短信界面的edittext需要把信息传给输入法界面的edittext,这里的流程是怎么样传递的?

android版本:8.1

在短信输入界面输入字符的时候的edittext,根据视图查找到这个view是ComposeMessageActivity.java的mTextEditor

mTextEditor = (EnhanceEditText) findViewById(R.id.embedded_text_editor);

我们知道,Edittext是继承自TextView的,有一个Editor是专门用来记录字符信息的。

在TextView的onDraw里有一个editor的onDraw,

看看Editor的onDraw方法

void onDraw(Canvas canvas, Layout layout, Path highlight, Paint highlightPaint,
        int cursorOffsetVertical) {

    。。。。
    final InputMethodState ims = mInputMethodState;
    if (ims != null && ims.mBatchEditNesting == 0) {
        InputMethodManager imm = InputMethodManager.peekInstance();
        if (imm != null) {
            if (imm.isActive(mTextView)) {
                if (ims.mContentChanged || ims.mSelectionModeChanged) {

                    reportExtractedText();
                }
            }
        }
    }
    。。。。
}

在画view的时候,editor有和InputMethod进行信息传递,使用了reportExtractedText()方法,

boolean reportExtractedText() {
    final Editor.InputMethodState ims = mInputMethodState;
    。。。
    InputMethodManager imm = InputMethodManager.peekInstance();
    。。。
    imm.updateExtractedText(mTextView, req.token, ims.mExtractedText);

}

在获取了InputMethodManager的对象后,调用了updateExtractedText方法,

public void updateExtractedText(View view, int token, ExtractedText text) {
    
    synchronized (mH) {

        if (mCurMethod != null) {
            try {
                mCurMethod.updateExtractedText(token, text);
            } catch (RemoteException e) {
            }
        }
    }
}

接着走mCurMethod.updateExtractedText,我们需要看看这个mCurMethod指向的是谁

查找mCurMethod发现,

IInputMethodSession mCurMethod;

而IInputMethodSession一看就知道是个接口,

oneway interface IInputMethodSession {}

这是AIDL实现,我们需要找到实现这个接口的服务,

class IInputMethodSessionWrapper extends IInputMethodSession.Stub

因为IInputMethodSessionWrapper继承了IInputMethodSession的stub,这是AIDL进程通信的方式,

在IInputMethodSessionWrapper我们可以找到updateExtractedText,

@Override
public void updateExtractedText(int token, ExtractedText text) {
    mCaller.executeOrSendMessage(mCaller.obtainMessageIO(
            DO_UPDATE_EXTRACTED_TEXT, token, text));
}

在这里,调用了mCaller去执行sendmessage的方式,用mcaller来调用update 的case,这是使用handler的写法,

查找mcaller的handlemessage,我们可以找到DO_UPDATE_EXTRACTED_TEXT,

case DO_UPDATE_EXTRACTED_TEXT:
    mInputMethodSession.updateExtractedText(msg.arg1,
            (ExtractedText)msg.obj);
    return;

在这里调用了mInputMethodSession的updateExtractedText,

InputMethodSession mInputMethodSession;
public interface InputMethodSession {

这里InputMethodSession也是个接口interface,不过他不是AIDL,直接找谁继承了这个接口

发现

public abstract class AbstractInputMethodService extends Service
public abstract class AbstractInputMethodSessionImpl implements InputMethodSession 

AbstractInputMethodService的内部类AbstractInputMethodSessionImpl继承了这个接口,但是它没有实现其中的方法,继续看AbstractInputMethodSessionImpl的子类,会发现

public class InputMethodService extends AbstractInputMethodService
public class InputMethodSessionImpl extends AbstractInputMethodSessionImpl 

这里走到了InputMethodService的内部类InputMethodSessionImpl,

InputMethodSessionImpl继承了AbstractInputMethodSessionImpl,InputMethodSessionImpl实现了接口中的方法,

实现方法是

public void updateExtractedText(int token, ExtractedText text) {
    if (!isEnabled()) {
        return;
    }
    Log.i(TAG, "updateExtractedText: text");
    onUpdateExtractedText(token, text);
}

继续追踪,

public void onUpdateExtractedText(int token, ExtractedText text) {

   mExtractEditText.setExtractedText(text);

}

看看这个mExtractEditText是什么

mExtractEditText = (ExtractEditText)view.findViewById(
        com.android.internal.R.id.inputExtractEditText);
全局搜索inputExtractEditText这个id,会发现调用这个id的布局文件是这样的
<android.inputmethodservice.ExtractEditText
        android:id="@+id/inputExtractEditText"
        android:layout_width="0px"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:scrollbars="vertical"
        android:gravity="top"
        android:minLines="1"
        android:inputType="text">
</android.inputmethodservice.ExtractEditText>

通过在前面查找view的时候看到的,

Android Edittext如何将信息传递给输入法inputmethod的流程

这里的视图显示

Android Edittext如何将信息传递给输入法inputmethod的流程

也就是说,在短信编辑界面跳出来的输入法输入框的id就是inputExtractEditText,对应的view就是上面所说的mExtractEditText,最后在mExtractEditText.setExtractedText(text)里实现了message短信界面和输入法输入框的文本信息传递。


总结:Edittext的输入信息和输入法的传递,其中走了很多传递,其中关于Textview的Editor是个比较难懂的地方,以及各种inputservice的类,当然这里只是走了一下关于信息如何传递的过程,中间的AIDL和接口方式,是面向对象编程的用法,需要理解。