標籤:android blog class code ext int
繼承於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);
上面的代碼:把有關按鍵下發給應用,即應用監聽IME按鍵事件
@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() {@Overridepublic 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)
現在我們明白了吧,搜尋和斷行符號等等按鍵就是這麼實現回調的