您的位置:首页 > 移动开发 > Android开发

android 应用监听输入法按键事件【比如搜索和回车键等】的整个流程分析

2014-05-08 14:48 375 查看
继承于InputMethodService类的服务代码如下:

int keyCode = sKey.getKeyCode();

KeyEvent eDown = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
keyCode, 0, 0, 0, 0, KeyEvent.FLAG_SOFT_KEYBOARD);
KeyEvent eUp = new KeyEvent(0, 0, KeyEvent.ACTION_UP, keyCode,
0, 0, 0, 0, KeyEvent.FLAG_SOFT_KEYBOARD);

onKeyDown(keyCode, eDown);
onKeyUp(keyCode, eUp);


上面的代码:把有关按键下发给应用,即应用监听输入法按键事件

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (processKey(event, 0 != event.getRepeatCount())) return true;
return super.onKeyDown(keyCode, event);
}

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (processKey(event, true)) return true;
return super.onKeyUp(keyCode, event);
}


上面的down和up,我们重点看onKeyUp,跟踪下日志,是下面直接返回true了

if (processKey(event, true)) return true;


进入该方法,在该方法里面有如下代码为其覆盖代码:

if (processFunctionKeys(keyCode, realAction)) {

return true;
}


再进入该方法processFunctionKeys,跟踪其走入了下面代码:

if (keyCode == KeyEvent.KEYCODE_ENTER) {

if (!realAction){
Log.d(TAG,"processFunctionKeys call KEYCODE_ENTER return");
return true;
}
sendKeyChar('\n');
return true;
}


因为上面realAction为传进来的true,所以执行了如下

sendKeyChar('\n');


进入该方法,该方法在InputMethodService中

public void sendKeyChar(char charCode) {
switch (charCode) {
case '\n': // Apps may be listening to an enter key to perform an action
if (!sendDefaultEditorAction(true)) {
sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
}
break;
default:
// Make sure that digits go through any text watcher on the client side.
if (charCode >= '0' && charCode <= '9') {
sendDownUpKeyEvents(charCode - '0' + KeyEvent.KEYCODE_0);
} else {
InputConnection ic = getCurrentInputConnection();
if (ic != null) {
ic.commitText(String.valueOf((char) charCode), 1);
}
}
break;
}
}


因为传进入的是'\n',所以执行了如下:

case '\n': // Apps may be listening to an enter key to perform an action
if (!sendDefaultEditorAction(true)) {
sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
}
break;


看上面注释:// Apps may be listening to an enter key to perform an action,很清楚吧,呵呵,来看看这个方法吧

public boolean sendDefaultEditorAction(boolean fromEnterKey) {
EditorInfo ei = getCurrentInputEditorInfo();
if (ei != null &&
(!fromEnterKey || (ei.imeOptions &
EditorInfo.IME_FLAG_NO_ENTER_ACTION) == 0) &&
(ei.imeOptions & EditorInfo.IME_MASK_ACTION) !=
EditorInfo.IME_ACTION_NONE) {
// If the enter key was pressed, and the editor has a default
// action associated with pressing enter, then send it that
// explicit action instead of the key event.
InputConnection ic = getCurrentInputConnection();
if (ic != null) {
ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION);
}
return true;
}

return false;
}


上面这个方法只是通知:让编辑器执行它,表示它可以做一个动作:

/**
* Have the editor perform an action it has said it can do.
*/
public boolean performEditorAction(int editorAction);

/**
* Set of bits in {@link #imeOptions} that provide alternative actions
* associated with the "enter" key.  This both helps the IME provide
* better feedback about what the enter key will do, and also allows it
* to provide alternative mechanisms for providing that command.
*/
public static final int IME_MASK_ACTION = 0x000000ff;


我们来看这个方法EditableInputConnection中,有关为什么是EditableInputConnection看我之前的帖子就会明白了

@Override
public boolean performEditorAction(int actionCode) {
if (DEBUG) Log.v(TAG, "performEditorAction " + actionCode);
mTextView.onEditorAction(actionCode);
return true;
}


一般应用程序想要监听回车或搜索按键则,如下写法:

edittext.setOnEditorActionListener(new TextView.OnEditorActionListener() {

@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
/*判断是否是“GO”键*/
if(actionId == EditorInfo.IME_ACTION_GO){

edittext.setText("success");

return true;
}
return false;
}
});


上面这个调用的是TextView中的接口

/**
* Interface definition for a callback to be invoked when an action is
* performed on the editor.
*/
public interface OnEditorActionListener {
/**
* Called when an action is being performed.
*
* @param v The view that was clicked.
* @param actionId Identifier of the action.  This will be either the
* identifier you supplied, or {@link EditorInfo#IME_NULL
* EditorInfo.IME_NULL} if being called due to the enter key
* being pressed.
* @param event If triggered by an enter key, this is the event;
* otherwise, this is null.
* @return Return true if you have consumed the action, else false.
*/
boolean onEditorAction(TextView v, int actionId, KeyEvent event);
}


上面的又是怎么实现的呢?

/**
* Set a special listener to be called when an action is performed
* on the text view.  This will be called when the enter key is pressed,
* or when an action supplied to the IME is selected by the user.  Setting
* this means that the normal hard key event will not insert a newline
* into the text view, even if it is multi-line; holding down the ALT
* modifier will, however, allow the user to insert a newline character.
*/
public void setOnEditorActionListener(OnEditorActionListener l) {
if (mInputContentType == null) {
mInputContentType = new InputContentType();
}
mInputContentType.onEditorActionListener = l;
}


我们看到了OnEditorActionListener l赋值给了mInputContentType.onEditorActionListener

那么我们再回到上面EditableInputConnection中的方法:

@Override
public boolean performEditorAction(int actionCode) {
if (DEBUG) Log.v(TAG, "performEditorAction " + actionCode);
mTextView.onEditorAction(actionCode);
return true;
}


进入如下方法:

mTextView.onEditorAction(actionCode);

public void onEditorAction(int actionCode) {
final InputContentType ict = mInputContentType;
if (ict != null) {
if (ict.onEditorActionListener != null) {
if (ict.onEditorActionListener.onEditorAction(this,
actionCode, null)) {
return;
}
}


看到了吧,之前放入mInputContentType的onEditorActionListener现在赋值给了InputContentType ict,然后执行了

ict.onEditorActionListener.onEditorAction(this,
actionCode, null)


现在我们明白了吧,搜索和回车等等按键就是这么实现回调的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: