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的时候看到的,
这里的视图显示
也就是说,在短信编辑界面跳出来的输入法输入框的id就是inputExtractEditText,对应的view就是上面所说的mExtractEditText,最后在mExtractEditText.setExtractedText(text)里实现了message短信界面和输入法输入框的文本信息传递。
总结:Edittext的输入信息和输入法的传递,其中走了很多传递,其中关于Textview的Editor是个比较难懂的地方,以及各种inputservice的类,当然这里只是走了一下关于信息如何传递的过程,中间的AIDL和接口方式,是面向对象编程的用法,需要理解。