原创文章,转载请标注出处----
我们知道当一个编辑框获得焦点的时候,将会create一个新的IME客户端,那么IMF框架是怎样处理这个事件的呢?
首先调用EditText的构造函数EditTex->TextView->setText()
InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null) imm.restartInput(this);
->startInputInner
void startInputInner() { final View view; synchronized (mH) { view = mServedView; // Make sure we have a window token for the served view. if (DEBUG) Log.v(TAG, "Starting input: view=" + view); if (view == null) { if (DEBUG) Log.v(TAG, "ABORT input: no served view!"); return; } } // Now we need to get an input connection from the served view. // This is complicated in a couple ways: we can't be holding our lock // when calling out to the view, and we need to make sure we call into // the view on the same thread that is driving its view hierarchy. Handler vh = view.getHandler(); if (vh == null) { // If the view doesn't have a handler, something has changed out // from under us, so just bail. if (DEBUG) Log.v(TAG, "ABORT input: no handler for view!"); return; } if (vh.getLooper() != Looper.myLooper()) { // The view is running on a different thread than our own, so // we need to reschedule our work for over there. if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread"); vh.post(new Runnable() { public void run() { startInputInner(); } }); return; } // Okay we are now ready to call into the served view and have it // do its stuff. // Life is good: let's hook everything up! EditorInfo tba = new EditorInfo(); tba.packageName = view.getContext().getPackageName(); tba.fieldId = view.getId(); InputConnection ic = view.onCreateInputConnection(tba); //create 新的InputConnection if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic); synchronized (mH) { // Now that we are locked again, validate that our state hasn't // changed. if (mServedView != view || !mServedConnecting) { // Something else happened, so abort. if (DEBUG) Log.v(TAG, "Starting input: finished by someone else (view=" + mServedView + " conn=" + mServedConnecting + ")"); return; } // If we already have a text box, then this view is already // connected so we want to restart it. final boolean initial = mCurrentTextBoxAttribute == null; // Hook 'em up and let 'er rip. mCurrentTextBoxAttribute = tba; mServedConnecting = false; mServedInputConnection = ic; IInputContext servedContext; if (ic != null) { mCursorSelStart = tba.initialSelStart; mCursorSelEnd = tba.initialSelEnd; mCursorCandStart = -1; mCursorCandEnd = -1; mCursorRect.setEmpty(); servedContext = new ControlledInputConnectionWrapper(vh.getLooper(), ic); } else { servedContext = null; } try { if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic=" + ic + " tba=" + tba + " initial=" + initial); InputBindResult res = mService.startInput(mClient, servedContext, tba, initial, mCurMethod == null); //启动IMEservice if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res); if (res != null) { if (res.id != null) { mBindSequence = res.sequence; mCurMethod = res.method; } else { // This means there is no input method available. if (DEBUG) Log.v(TAG, "ABORT input: no input method!"); return; } } if (mCurMethod != null && mCompletions != null) { try { mCurMethod.displayCompletions(mCompletions); } catch (RemoteException e) { } } } catch (RemoteException e) { Log.w(TAG, "IME died: " + mCurId, e); } }
那么到了IME部分的流程又是如何的呢?
首先收到configure change的event调用onConfigurationChanged->inputmethodservice.onConfigurationChanged(conf)
@Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); boolean visible = mWindowVisible; int showFlags = mShowInputFlags; boolean showingInput = mShowInputRequested; CompletionInfo[] completions = mCurCompletions; initViews(); mInputViewStarted = false; mCandidatesViewStarted = false; if (mInputStarted) { doStartInput(getCurrentInputConnection(), getCurrentInputEditorInfo(), true); //调用startinput,创建IME的input } if (visible) { if (showingInput) { // If we were last showing the soft keyboard, try to do so again. if (onShowInputRequested(showFlags, true)) { showWindow(true); if (completions != null) { mCurCompletions = completions; onDisplayCompletions(completions); } } else { hideWindow(); } } else if (mCandidatesVisibility == View.VISIBLE) { // If the candidates are currently visible, make sure the // window is shown for them. showWindow(false); } else { // Otherwise hide the window. hideWindow(); } } }
doStartInput->initialize->onInitializeInterface->onStartInput->onStartInputView.
onStartInputView中会handle各种IME的event并进一步调用IME自身的onCreate函数,做进一步的初始化以及receiver的rigister。