android开发浅谈之InputMethodManagerService
Posted hfreeman2008
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android开发浅谈之InputMethodManagerService相关的知识,希望对你有一定的参考价值。
来到新公司,负责了输入法的问题处理和一些输入法相关的功能开发,所以对输入法有了一点点了解,所以写了这篇文章来从系统的角度浅谈一下输入法。
输入法管理服务的整体框架
输入法的整件框架:
输入法管理服务InputMethodManagerService主要包括三个模块:
- 第一个是app应用进程:
此部分可以使用InputMethodManager类来发起显示输入法或隐藏输入法的请求,也可以配置输入法的一些属性。
- 第二个是输入法应用进程:
这个就是我们通常意义上说的输入法应用,其主是InputMethodService的一个实现类,如qq输入法,搜狗输入法。
- 第三个是系统SystemServer进程的InputMethodManagerService类:
这个才是输入法的管理核心类。
输入法应用–InputMethodService
我们先讨论输入法应用部分:
以android内置的输入法LatinIME为例,
先看LatinIME输入的AndroidManifest.xml对其定义:
<service android:name="LatinIME"
android:label="@string/english_ime_name"
android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod" />
</intent-filter>
<meta-data android:name="android.view.im" android:resource="@xml/method" />
</service>
从这可以看出,LatinIME是一个service。
再看LatinIME类:
public class LatinIME extends InputMethodService implements KeyboardActionListener,
SuggestionStripView.Listener, SuggestionStripViewAccessor,
DictionaryFacilitator.DictionaryInitializationListener,
PermissionsManager.PermissionsResultCallback
可以看出,输入法LatinIME是InputMethodService的实现类。
那InputMethodService是什么呢?
请看下面InputMethodService的类图:
InputMethodService的类图清楚的表示其是一个带Dialog的Service,所以,输入法应用可以简单的理解为一个带Dialog的Service。
InputMethodService类中的mInputView 对应类LatinIME.mInputView,而LatinIME.mInputView对应KeyboardSwitcher.onCreateInputView方法中的mCurrentInputView :
public View onCreateInputView(final boolean isHardwareAcceleratedDrawingEnabled)
......
mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(
R.layout.input_view, null);
下面我们讲解app应用如何显示输入法界面,而InputMethodManagerService类是如何响应app的调用显示输入法。
app应用调用显示输入法和隐藏输入法
以我们在app应用中,点击一个输入框,显示输入法为例:
1.初始化InputMethodManager:
在InputMethodManager.InputMethodManager添加堆栈信息:
private InputMethodManager(IInputMethodManager service, int displayId, Looper looper)
Log.v(TAG, "InputMethodManager " ,new Throwable());
其打印信息:
android.view.inputmethod.InputMethodManager.<init>(InputMethodManager.java:955)
android.view.inputmethod.InputMethodManager.createRealInstance(InputMethodManager.java:904)
android.view.inputmethod.InputMethodManager.createInstance(InputMethodManager.java:892)
android.view.inputmethod.InputMethodManager.forContextInternal(InputMethodManager.java:988)
android.view.inputmethod.InputMethodManager.forContext(InputMethodManager.java:977)
android.app.SystemServiceRegistry$27.getService(SystemServiceRegistry.java:457)
android.app.SystemServiceRegistry$27.getService(SystemServiceRegistry.java:454)
android.app.SystemServiceRegistry.getSystemService(SystemServiceRegistry.java:1366)
android.app.ContextImpl.getSystemService(ContextImpl.java:1809)
android.content.ContextWrapper.getSystemService(ContextWrapper.java:752)
2.调用InputMethodManager.startInputInner接口
在InputMethodManager.startInputInner中添加堆栈信息:
boolean startInputInner(@StartInputReason int startInputReason,
@Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags,
@SoftInputModeFlags int softInputMode, int windowFlags)
......
try
if (DEBUG) Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic="
+ ic + " tba=" + tba + " startInputFlags="
+ InputMethodDebug.startInputFlagsToString(startInputFlags));
Log.v(TAG, "startInputInner mService.startInputOrWindowGainedFocus" ,new Throwable());
final InputBindResult res = mService.startInputOrWindowGainedFocus(
startInputReason, mClient, windowGainingFocus, startInputFlags,
softInputMode, windowFlags, tba, servedContext, missingMethodFlags,
view.getContext().getApplicationInfo().targetSdkVersion);
......
其打印信息:
android.view.inputmethod.InputMethodManager.startInputInner(InputMethodManager.java:1772)
android.view.inputmethod.InputMethodManager.checkFocus(InputMethodManager.java:1920)
android.view.inputmethod.InputMethodManager.viewClicked(InputMethodManager.java:2204)
android.widget.TextView.viewClicked(TextView.java:12914)
android.widget.TextView.onTouchEvent(TextView.java:10915)
android.view.View.dispatchTouchEvent(View.java:13980)
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3083)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2778)
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3083)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2778)
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3083)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2778)
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3083)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2778)
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3083)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2778)
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3083)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2778)
com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:481)
com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1854)
android.app.Activity.dispatchTouchEvent(Activity.java:4030)
androidx.appcompat.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:69)
com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:439)
android.view.View.dispatchPointerEvent(View.java:14239)
android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5767)
android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5564)
android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5067)
android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5120)
android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5086)
android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5226)
android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5094)
android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5283)
android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5067)
android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5120)
android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5086)
android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5094)
android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5067)
android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7796)
android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7765)
android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7726)
android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7921)
android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:189)
android.os.MessageQueue.nativePollOnce(Native Method)
android.os.MessageQueue.next(MessageQueue.java:336)
android.os.Looper.loop(Looper.java:181)
android.app.ActivityThread.main(ActivityThread.java:7574)
java.lang.reflect.Method.invoke(Native Method)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)
我们简单的看一下几个核心的接口:
TextView.onTouchEvent
public boolean onTouchEvent(MotionEvent event)
......
if (touchIsFinished && (isTextEditable() || textIsSelectable))
// Show the IME, except when selecting in read-only text.
final InputMethodManager imm = getInputMethodManager();
viewClicked(imm);//确认view click
if (isTextEditable() && mEditor.mShowSoftInputOnFocus && imm != null)
imm.showSoftInput(this, 0);//显示输入法
......
TextView.viewClicked
protected void viewClicked(InputMethodManager imm)
if (imm != null)
imm.viewClicked(this);//调用imm.viewClicked
InputMethodManager.viewClicked
public void viewClicked(View view)
.....
final boolean focusChanged = mServedView != mNextServedView;
checkFocus();//调用checkFocus
InputMethodManager.checkFocus
public void checkFocus()
if (checkFocusNoStartInput(false))
startInputInner(StartInputReason.CHECK_FOCUS, null, 0, 0, 0);//调用startInputInner
InputMethodManager.startInputInner
boolean startInputInner(@StartInputReason int startInputReason,
@Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags,
@SoftInputModeFlags int softInputMode, int windowFlags)
......
try
if (DEBUG) Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic="
+ ic + " tba=" + tba + " startInputFlags="
+ InputMethodDebug.startInputFlagsToString(startInputFlags));
final InputBindResult res = mService.startInputOrWindowGainedFocus(
startInputReason, mClient, windowGainingFocus, startInputFlags,
softInputMode, windowFlags, tba, servedContext, missingMethodFlags,
view.getContext().getApplicationInfo().targetSdkVersion);//调用mService.startInputOrWindowGainedFocus
......
我们可以从上面的日志信息明确看到我们点击输入框,系统如何从:
TextView.onTouchEvent----InputMethodManager.viewClicked----InputMethodManager.startInputInner----InputMethodManagerService.startInputOrWindowGainedFocus
下面就是其类图:
3.InputMethodManagerService类发送消息MSG_START_INPUT
在InputMethodManagerService.handleMessage中添加堆栈信息:
public boolean handleMessage(Message msg)
Slog.v(TAG, "handleMessage getcaller:" ,new Throwable());
Slog.v(TAG, "handleMessage msg.what:" + msg.what);
在接上面InputMethodManagerService.startInputOrWindowGainedFocus接口调用后,打印日志信息:
com.android.server.inputmethod.InputMethodManagerService.handleMessage(InputMethodManagerService.java:3810)
com.android.server.inputmethod.InputMethodManagerService.executeOrSendMessage(InputMethodManagerService.java:2013)
com.android.server.inputmethod.InputMethodManagerService.attachNewInputLocked(InputMethodManagerService.java:2080)
com.android.server.inputmethod.InputMethodManagerService.startInputUncheckedLocked(InputMethodManagerService.java:2208)
com.android.server.inputmethod.InputMethodManagerService.startInputOrWindowGainedFocusInternalLocked(InputMethodManagerService.java:3171)
com.android.server.inputmethod.InputMethodManagerService.startInputOrWindowGainedFocus(InputMethodManagerService.java:3076)
com.android.internal.view.IInputMethodManager$Stub.onTransact(IInputMethodManager.java:331)
com.android.server.inputmethod.InputMethodManagerService.onTransact(InputMethodManagerService.java:1636)
android.os.Binder.execTransactInternal(Binder.java:1021)
android.os.Binder.execTransact(Binder以上是关于android开发浅谈之InputMethodManagerService的主要内容,如果未能解决你的问题,请参考以下文章
android开发浅谈之InputMethodManagerService
android开发浅谈之InputMethodManagerService
android开发浅谈之PackageManagerService(pkms)
android开发浅谈之PackageManagerService(pkms)