简书android 输入法设置,Android输入法弹出流程

本文详细解析了Android 9.x系统中输入法的弹出流程,从`viewClicked`开始,经过`checkFocus`、`startInputInner`等一系列步骤,最终由`InputMethodManager`和服务端交互实现输入法的显示。文章深入探讨了输入法窗口和应用窗口的绑定、输入连接的创建以及输入法显示的条件判断等关键环节。
摘要由CSDN通过智能技术生成

基于Android 9.x

目录

1 viewClicked流程

1.1 viewClicked

1.2 checkFocus

1.3 startInputInner

1.4 startInputOrWindowGainedFocus

1.5 startInputLocked

1.6 startInputUncheckedLocked

1.7 attachNewInputLocked

1.7.1 处理返回的结果

2 showSoftInput流程

2.1 showSoftInput

2.2 IMMS#showSoftInput

2.3 showCurrentInputLocked

2.4 IMS$InputMethodImpl$showSoftInput

2.5 dispatchOnShowInputRequested

2.6 IMS$showWindow

2.7 showWindowInner

输入法弹出流程

d0b001a055c1?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

输入法#拉起流程#输入框弹出流程.png

viewClicked流程

viewClicked

IMM.JAVA

public void viewClicked(View view) {attachNewInputLocked

//服务的view是否相同,当两次点击在同一个输入框时,两者相同;否则不同

//我们首次点击某个输入框为例

final boolean focusChanged = mServedView != mNextServedView;

checkFocus();

synchronized (mH) {

if ((mServedView != view && (mServedView == null

|| !mServedView.checkInputConnectionProxy(view)))

|| mCurrentTextBoxAttribute == null || mCurMethod == null) {

return;

}

try {

if (DEBUG) Log.v(TAG, "onViewClicked: " + focusChanged);

mCurMethod.viewClicked(focusChanged);

} catch (RemoteException e) {

Log.w(TAG, "IME died: " + mCurId, e);

}

}

}

checkFocus

public void checkFocus() {

//检查该view是否已经执行过startInputInner

//主要是比较最后一个mServedView和当前mNextServedView是否相同

//该方法逻辑已经在"输入法窗口和应用窗口绑定."讲过,本章节不在介绍

if (checkFocusNoStartInput(false)) {

startInputInner(InputMethodClient.START_INPUT_REASON_CHECK_FOCUS, null, 0, 0, 0);

}

}

startInputInner

携带的参数:

-startInputReason:START_INPUT_REASON_CHECK_FOCUS,标明本次调用的目的

-windowGainingFocus:会影响IMMS中startInputOrWindowGainedFocus的调用逻辑

-controlFlags,softInputMode,windowFlags = 0

boolean startInputInner(@InputMethodClient.StartInputReason final int startInputReason,

IBinder windowGainingFocus, int controlFlags, int softInputMode,

int windowFlags) {

final View view;

synchronized (mH) {

//mServedView已经在checkFocusNoStartInput中赋值为mNextServedView,因此这里为当前要获取输入法焦点的view

view = mServedView;

// Make sure we have a window token for the served view.

if (DEBUG) {

Log.v(TAG, "Starting input: view=" + dumpViewInfo(view) +

" reason=" + InputMethodClient.getStartInputReason(startInputReason));

}

if (view == null) {

if (DEBUG) Log.v(TAG, "ABORT input: no served view!");

return false;

}

}

// 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 close the current input.

// If we don't close the current input, the current input method can remain on the

// screen without a connection.

if (DEBUG) Log.v(TAG, "ABORT input: no handler for view! Close current input.");

closeCurrentInput();

return false;

}

//判断view是否在UI主线程

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(() -> startInputInner(startInputReason, null, 0, 0, 0));

return false;

}

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

// Note: Use Context#getOpPackageName() rather than Context#getPackageName() so that the

// system can verify the consistency between the uid of this process and package name passed

// from here. See comment of Context#getOpPackageName() for details.

tba.packageName = view.getContext().getOpPackageName();

tba.fieldId = view.getId();

//通过TextView的onCreateInputConnection方法初始化,EditorInfo,主要是获取inputType和imeOptions

//ic是一个EditableInputConnection,用来跟IMS通信

InputConnection ic = view.onCreateInputConnection(tba);

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.

//正常情况下不会出现mServedView != view,多线程操作会。

//mServedConnecting在checkFocusNoStartInput过程中,被置位true,为false表示startInputInner被多次执行

if (mServedView != view || !mServedConnecting) {

// Something else happened, so abort.

if (DEBUG) Log.v(TAG,

"Starting input: finished by someone else. view=" + dumpViewInfo(view)

+ " mServedView=" + dumpViewInfo(mServedView)

+ " mServedConnecting=" + mServedConnecting);

return false;

}

// If we already have a text box, then this view is already

// connected so we want to restart it.

if (mCurrentTextBoxAttribute == null) {

controlFlags |= CONTROL_START_INITIAL;

}

// Hook 'em up and let 'er rip.

mCurrentTextBoxAttribute = tba;

//置位false,与checkFocusNoStartInput同步该参数状态

mServedConnecting = false;

if (mServedInputConnectionWrapper != null) {

mServedInputConnectionWrapper.deactivate();

mServedInputConnectionWrapper = null;

}

ControlledInputConnectionWrapper servedContext;

final int missingMethodFlags;

//对于EditorText,不为null

if (ic != null) {

mCursorSelStart = tba.initialSelStart;

mCursorSelEnd = tba.initialSelEnd;

mCursorCandStart = -1;

mCursorCandEnd = -1;

mCursorRect.setEmpty();

mCursorAnchorInfo = null;

final Handler icHandler;

missingMethodFlags = InputConnectionInspector.getMissingMethodFlags(ic);

if ((missingMethodFlags & InputConnectionInspector.MissingMethodFlags.GET_HANDLER)

!= 0) {

// InputConnection#getHandler() is not implemented.

icHandler = null;

} else {

icHandler = ic.getHandler();

}

//创建ControlledInputConnectionWrapper

servedContext = new ControlledInputConnectionWrapper(

icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this);

} else {

servedContext = null;

missingMethodFlags = 0;

}

//The InputConnection that was last retrieved from the served view.

mServedInputConnectionWrapper = servedContext;

try {

if (DEBUG) Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic="

+ ic + " tba=" + tba + " controlFlags=#"

+ Integer.toHexString(controlFlags));

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值