1. 程式人生 > >Android開發例項詳解之IMF(輸入法)(Android SDK Sample—SoftKeyboard)

Android開發例項詳解之IMF(輸入法)(Android SDK Sample—SoftKeyboard)

      本博前面的文章介紹了開發環境的搭建和模擬器的常用操作。本次,將以Android Sample中經典的SoftKeyboard專案為例,詳細解析Android上一個小型專案的開發過程和注意事項。

  從SDK 1.5版本以後,Android就開放它的IMF(Input Method Framework),讓我們能夠開發自己的輸入法。而開發輸入法最好的參考就是Android自帶的Sample-SoftKeyboard,雖然這個例子僅包含英文和數字輸入,但是它本身還算完整和清楚,對我們開始實戰有很大幫助。
  一、IMF簡介

  一個IMF結構中包含三個主要的部分:

  input method manager:管理各部分的互動。它是一個客戶端API,存在於各個應用程式的context中,用來溝通管理所有程序間互動的全域性系統服務。


  input method(IME):實現一個允許使用者生成文字的獨立互動模組。系統繫結一個當前的輸入法。使其建立和生成,決定輸入法何時隱藏或者顯示它的UI。同一時間只能有一個IME執行。
  client application:通過輸入法管理器控制輸入焦點和IME的狀態。一次只能有一個客戶端使用IME。

  1、InputManager
  由UI控制元件(View,TextView,EditText等)呼叫,用來操作輸入法。比如,開啟,關閉,切換輸入法等。
  它是整個輸入法框架(IMF)結構的核心API,處理應用程式和當前輸入法的互動。可以通過Context.getSystemService()來獲取一個InputMethodManager的例項。


  在開發過程中,最基礎最重要的就是養成閱讀API的習慣。優秀的程式設計師要養成把自己關在小黑屋裡,斷絕與外界的聯網和聯絡,僅僅靠自己電腦中的開發環境和API文件,以及漂亮女僕送來的每天三頓飯,寫出優秀的程式。這個在武俠小說中叫閉關,在軟體開發中叫Clean Room,哈哈。
  Android的API文件在:%SDK_ROOM%/docs/reference/index.html,
  InputManager類的位置:%SDK_ROOM%/docs/reference/android/view/inputmethod/InputMethodManager.html
  由於,該類跟本次要講的Sample關係不大,這裡就不詳細分析,請各位自行閱讀API doc吧。

  2、InputMethodService
  包括輸入法內部邏輯,鍵盤佈局,選詞等,最終把選出的字元通過commitText提交出來。實現輸入法的基礎就是名為InputMethodService的類,比如你要實現一個谷歌輸入法,就是要extends本類。我們接下來要學習的SoftKeyboard Sample也是extends本類。InputMethodService類的位置在:%SDK_ROOM%/docs/reference/android/inputmethodservice/InputMethodService.html
  InputMethodService是InputMethod的一個完整實現,你可以再在其基礎上擴充套件和定製。它的主要方法如下:
  onInitializeInterface() 顧名思義,它在初始化介面的時候被呼叫,而一般是由於配置檔案的更改導致該函式的執行
  onBinndInput() 它在另外的客戶端和該輸入法連線時呼叫
  onStartInput() 非常重要的一個回撥,它在編輯框中使用者已經開始輸入的時候呼叫。比如,當點選一個輸入框,我們需要根據這個輸入框的資訊,設定輸入法的一些特性,這個在Sample中很有體會。
  onCreateInputView() 返回一個層次性的輸入檢視,而且只是在這個檢視第一次顯示的時候被呼叫
  onCreateCandidatesView() 同onCreateInputView(),只不過建立的是候選框的檢視。
  onCreateExtractTextView() 比較特殊,是在全屏模式下的一個檢視。
  onStartInputView() 在輸入檢視被顯示並且在一個新的輸入框中輸入已經開始的時候呼叫。
  基本上輸入法的定製,都是圍繞在這個類來實現的,它主要提供的是一個基本的使用者介面框架(包括輸入檢視,候選詞檢視和全屏模式),但是這些都是要實現者自己去定製的。這裡的實現是讓所有的元素都放置在了一個單一的由InputMethodService來管理的視窗中。它提供了很多的回撥API,需要我們自己去實現。一些預設的設定包括:
  軟鍵盤輸入檢視,它通常都是被放置在螢幕的下方。
  候選詞檢視,它通常是放置在輸入檢視的上面。
  當我們輸入的時候,需要改變應用程式的介面來適應這些檢視的放置規則。比如在Android上面輸入,編輯框會自動變形騰出一個軟鍵盤的位置來。
  兩個非常重要的檢視:
  1. 軟輸入檢視。是與使用者互動的主要發生地:按鍵,畫圖或者其他的方式。通常的實現就是簡單的用一個檢視來處理所有的工作,並且在呼叫 onCreateInputView()的時候返回一個新的例項。通過呼叫系統的onEvaluateInputViewShow()來測試是否需要顯示輸入檢視,它是系統根據當前的上下文環境來實現的。當輸入法狀態改變的時候,需要呼叫updateInputViewShown()來重新估計一下。
  2. 候選詞檢視。當用戶輸入一些字元之後,輸入法可能需要提供給使用者一些可用的候選詞的列表。這個檢視的管理和輸入檢視不大一樣,因為這個檢視是非常的短暫的,它只是在有候選詞的時候才會被顯示。可以用setCandidatesViewShow()來設定是否需要顯示這個檢視。正是因為這個顯示的頻繁性,所以它一般不會被銷燬,而且不會改變當前應用程式的檢視。
  最後,關於文字的產生,這是一個IME的最終目的。它通過InputConnection來連結IME和應用程式的:能夠直接產生想要的按鍵資訊,甚至直接在候選和提交的文字中編輯。當用戶在不同的輸入目標之間切換的時候,IME會不斷的呼叫onFinishInput() 和 onStartInput()。在這兩個函式中,需要反覆做的就是復位狀態,並且應對新的輸入框的資訊。
  以上是一個輸入法的最基本的介紹,下面將根據Sample中的SoftKeyboard來說明這些問題。

  二、建立Eclipse工程
  這裡使用最新版本的 2.3.3下的SoftKeyboard Sample來建立工程,其實,從1.5版本,該Sample就已經存在了。同時,由於SoftKeyboard會使人誤解為KeyBoard的子類,這裡特別改名為InputMethodServiceSample,更符合其功能和特性。


  點選Finish,完成專案的建立,可以看到專案工程結構如下:


  在Android SDK 2.3.3模擬器上執行本Sample,需要在Setting中選擇使用本Sample,需要在Language&keyboard中選中本Sample的名稱。


  當嘗試選中Sample Soft Keyboard時,Android會出現安全提示。IME的確要選擇自己信任的,因為它可以收集和記錄所有你的輸入,這個特性如果被有心人利用會很恐怖。
  選中Sample Soft Keyboard作為我們的輸入法之後,進入需要輸入法的地方,這裡以簡訊介面作為範例,在輸入框中長按,會出現“編輯文字”選單,點選“輸入法”即可進入當前輸入介面的輸入法選擇框。就可以使用輸入法切換到本輸入法看到它的keyboard。


  之後就可以看到Soft keyboard鍵盤如下:


  三、配置和資原始檔解析
  除去原始碼將在後文統一分析之外,這裡介紹下配置和資原始檔。
  1. AndroidMainifest.xml
  每個都會有的配置描述檔案。在這裡,Sample把自己宣告成了服務,而且繫結在了輸入法之上。它的intent-filter是直接用的InputMethod介面,這也是所有的輸入法的介面。
  2. res目錄
  放置resource,即資原始檔,裡面蠻多東西的,具體如下。
  (1) drawable目錄,放置的是圖示檔案。
  (2) values目錄,包含strings.xml以及一些自定義的型別和值的xml檔案。
  strings.xml
  ― ime_name 定義了該輸入法的名字
  ― word_separators 詞的分隔符,即輸入過程中可能用來表示一個詞輸入完成的符號,比如空格,標點等等)
  ― label_xx_key 為軟鍵盤定義確認鍵的標籤。在後面程式碼解析中可以看到,程式會根據輸入框的資訊來設定EnterKey的圖示或者標籤。如:在一個網址上面輸入,就會顯示一個搜尋的圖示,而在編輯簡訊時,如果在收信人寫,那麼EnterKey就是Next標籤,用來直接跳到簡訊正文部分。
  dimens.xml,定義軟鍵盤的尺寸資訊,包括鍵高(key_height),候選詞字型的高度(candidate_font_height),候選詞垂直間隙(candidate_vertical_padding)。
  color.xml,定義候選詞的背景顏色,比如正常(candidate_normal),推薦(candidate_recommended),背景(candidate_background)和其它(candidate_other)等顏色。
  (3) layout目錄,儲存佈局配置檔案。這裡只有一個配置檔案:input.xml,它定義的是輸入檢視的資訊,包括id(android:id="@+id/keyboard"),放置在螢幕下方(android:layout_alignParentBottom="true"),水平最大填充(android:layout_width="match_parent"),垂直包含子內容(android:layout_height="wrap_content")。
  (4) xml目錄,檔案如下:
  method.xml,為搜尋管理提供配置資訊。
  qwerty.xml,英文字元的全鍵盤佈局檔案。定義很直觀,很容易就可以看懂。
  symbols_shift.xml和symbols.xml,是標點字元的全鍵盤佈局檔案。

  四、原始碼解析
  (一)概述
  從InputMethodServiceSample專案可以看出實現一個輸入法至少需要CandidateView, LatinKeyboard, LatinKeyboardView,SoftKeyboard這四個檔案:
  CandidateView負責顯示軟鍵盤上面的那個候選區域。
  LatinKeyboard負責解析並儲存鍵盤佈局,並提供選詞演算法,供程式運行當中使用。其中鍵盤佈局是以XML檔案存放在資源當中的。比如我們在漢字輸入法下,按下b、a兩個字母。LatinKeyboard就負責把這兩個字母變成爸、把、巴等顯示在CandidateView上。
  LatinKeyboardView負責顯示,就是我們看到的按鍵。它與CandidateView合起來,組成了InputView,就是我們看到的軟鍵盤。
  SoftKeyboard繼承了InputMethodService,啟動一個輸入法,其實就是啟動一個InputMethodService,當SoftKeyboard輸入法被使用時,啟動就會啟動SoftKeyboard這個Service。
  (二)LatinKeyboard.java
  軟鍵盤類,直接繼承了Keyboard類,並定義一個xml格式的Keyboard的佈局,來實現一個輸入拉丁文的鍵盤。這裡只是建立一個鍵盤物件,並不對具體的佈局給出手段。
  為了更好的理解LatinKeyboard類,這裡簡單介紹一下Keyboard類。Keyboard可以載入一個用來顯示鍵盤佈局的xml來初始化自己,並且可以儲存這些鍵盤的鍵的屬性。他有三個建構函式:
  Keyboard(Context context, int xmlLayoutResId),用語境和xml資源id索引xml檔案來建立。
  Keyboard(Context context, int xmlLayoutResId, int modeId),這個和上面差不多,只不過多了一個modeld。
  Keyboard(Context context, int layoutTemplateResId, CharSequence characters, int columns, int horizontalPadding),這個比較複雜,用一個空xml佈局模板建立一個鍵盤,然後用指定的characters按照從左往右,從上往下的方式填滿這個模板。
  本檔案原始碼前面完全繼承keyboard,直接用了父類建構函式進行初始化。
  這裡因為重寫了Keyboard類的createKeyFromXml(Resources res, Row parent, int x, int y, XmlResourceParser parser),為了要返回一個Key物件,乾脆直接建立LatinKey物件好了。從這裡我們能看出面向物件和使用框架的要求。
  接著,本檔案過載了一個createKeyFromXml的函式,這是一個回撥函式,它在鍵盤描繪鍵的時候呼叫,從一個xml資原始檔中載入一個鍵,並且放置在(x,y)座標處。它還判斷了該鍵是否是回車鍵,並儲存起來。在這裡,為了要返回一個Key物件,於是直接建立內部類的LatinKey物件。從這裡我們能看出面向物件和使用框架的要求。
  此外,還有一個函式是:setImeOptions,它是根據編輯框的當前資訊,來為這個鍵盤的回車鍵設定適當的標籤。輸入框的不同,會產生不同的回車鍵的label或者icon。在這個函式中,有一個技巧是用了一些imeOption的位資訊,比如IME_MASK_ACTION等等。主要是檢視的EditorInfo的Action資訊,這裡有:
  IME_ACTION_GO: go操作,將使用者帶入到一個該輸入框的目標的動作。確認鍵將不會有icon,只有label: GO
  IME_ACTION_NEXT: next操作,將使用者帶入到該文字框的寫一個輸入框中。如: 編輯短訊息的時候,內容就是收件人手機號碼框的next文字域。它也只是一個NEXT label就行了。
  IME_ACTION_SEARCH: search操作,預設動作就是搜尋。如: 在URL框中輸入的時候,預設的就是search操作,它提供了一個像放大鏡一樣的icon。
  IME-ACTION_SEND: send操作,預設動作就是傳送當前的內容。如: 短訊息的內容框裡面輸入的時候,後面通常就是一個傳送操作。它也是隻提供一個Label:SEND
  DEFAULT: 預設情況下表示文字框並沒有什麼特殊的要求,所以只需要設定return的icon即可。
  最後,它還定義了一個內部類——LatinKey,它直接繼承了Key,來定義一個單獨的鍵,它唯一過載的函式是isInside(int x , int y ),用來判斷一個座標是否在該鍵內。它過載為判斷該鍵是否是CANCEL鍵,如果是則把Y座標減少10px,按照他的解釋是用來還原這個可以關掉鍵盤的鍵的目標區域。
  (三)LatinKeyboardView.java
  這裡就是個View,自然也繼承自View,因為前面建立的鍵盤只是一個概念,並不能例項出來一個UI,所以需要藉助於一個VIEW類來進行繪製。這個類簡單的繼承了KeyboardView類,然後過載了一個動作方法,就是onLongPress。
  它在有長時間按鍵事件的時候會呼叫,首先判斷這個按鍵是否是CANCEL鍵,如果是的話就通過呼叫 KeyboardView被安置好的OnKeyboardActionListener物件,給鍵盤傳送一個OPTIONS鍵被按下的事件。它是用來遮蔽CANCEL鍵,然後傳送了一個未知的程式碼的鍵。
  (四)CandidateView.java
  CandidateView是一個候選字顯示view,它提供一個候選字選擇的檢視,直接繼承於View類即可。在我們輸入字元時,它應該能根據字元顯示一定的提示,比如拼音同音字啊,聯想的字啊之類的。
  1. 先看它定義了那些重要變數:
  mService: candidateView的宿主類,即該view是為什麼輸入法服務的。
  mSuggestions: 建議。比如說當我們輸入一些字母之後輸入法希望根據輸入來進行聯想建議。
  mSelectedIndex: 使用者選擇的詞的索引。
  mSelectionHighlight: 描繪選擇區域高亮的類。
  mTypedWordValid: 鍵入的word是否合法正確。
  mBgPadding: 背景填充區域。
  mWordWidth: 每個候選詞的寬度。
  mWordX:每個候選詞的X座標。有了這兩個變數,就能夠在螢幕上準確的繪製出該候選鍵。
  mColor*:定義了各種顏色。
  mPaint: 一個繪圖類,後面會用到
  mVerticalPadding: 垂直填充區域。
  mTargetScrollX: 目標滾動的橫座標,即要將目標滾動到何處。
  mTotalWidth: 總的寬度
  mGestureDetector: 宣告一個手勢監測器
  GestureDetector物件似乎很少見,讓我們瞭解一下android.view.GestureDetector。這是一個與動作事件相關的類,可以用來檢測各種動作事件,這裡稱之為:手勢監測器。它的回撥函式是GestureDetector.OnGestureListener,在動作發生時執行,而且只能在觸控時發出,用滾動球無效。要使用這個通常要先建立一個物件,如同程式碼裡體現的,然後設定GestureDetector.OnGestureListener 同時在 onTouchEvent(MotionEvent)中寫入動作發生要執行的程式碼。
  2. 建構函式,主要是對一些變數的初始化工作。
  首先初始化了mSelectionHighlight,這是一個drawable物件,並利用drawable的setState方法設定這個drawable的初始狀態。同時在res目錄下加入一個color.xml檔案來定義用到的所有顏色資源,然後用R索引,這些資源可以被加入到自己的R.java的內容裡,可以直接引用。剩下的內容就是初始化背景,選中,未選中時的view的背景顏色,這裡都是在前面color.xml內定義的了。用這樣的方式獲得:
  Resources r = context.getResources();
  獲得當前資源物件的方法。
  setBackgroundColor(r.getColor(R.color.candidate_background));
  然後初始化了一個手勢檢測器(gesturedetector),它的Listener過載了一個方法,就是onScroll,這個類是手勢檢測器發現有scroll動作的時候觸發。在這個函式裡,主要是進行滑動的判斷。
  這裡用到了很多view下的方法:getScrollX();getWidth();scrollTo(sx, getScrollY());invalidate();我們分別解釋如下:
  getScrollX():獲得滾動後view的橫座標
  scrollTo():滾動到目標座標
  getScrollY():獲得滾動後view的縱座標
  invalidate():使view重畫
  在這裡,distanceX是上次呼叫onscroll後滾動的X軸距離。假設這個view之前沒有被滾動過,第一次滾動且座標在顯示區域內,sx=getScrollX()+distanceX,則view就scrollTo這個位置。如果sx超過了最大顯示寬度,則scrollTo就滾想原先sx處,也就是不動。也就是說:系統滾動產生一個慣性的感覺,當你把view實際到了X座標點,系統再給你加一個distanceX,這個distanceX不是兩個動作之間的距離,應該是上一個滾動動作的停止點和本次滾動動作的停止點之間的距離,這個距離系統自己算,我們不用管,只要到了最大邊界,view就不再滾動,或者說是原地滾動。
  接下來:
  setHorizontalFadingEdgeEnabled(true);// 設定view在水平滾動時,水平邊是否淡出。
  setWillNotDraw(false);// view不自己繪製自己
  setHorizontalScrollBarEnabled(false);// 不設定水平滾動條
  setVerticalScrollBarEnabled(false);// 不設定垂直滾動條
  3. setService是設定宿主輸入法。
  4. computeHorizontalScrollRange,表示這個view的水平滾動區域,返回的是候選檢視的總體寬度。
  5. onMeasure,過載自view類,在佈局階段被父檢視所呼叫。比如當父檢視需要根據其子檢視的大小來進行佈局時,就需要回調這個函式來看該view的大小。當呼叫這個函式時必須在內部呼叫setMeasureDimension來對寬和高進行儲存,否則將會有異常出現。這裡過載它是為了系統檢測要繪製的字元區的大小,因為字型可能有大小,應根據字型來。它首先計算自己的期望的寬度,呼叫resolveSize來看是否能夠得到50px的寬度;然後是計算想要的高度,根據字型和顯示提示區的padding來確定。
  6. onDraw,view的主要函式,每個view都必須重寫這個函式來繪製自己。它提供了一塊畫布,如果為空,則直接呼叫父類來畫。
  在這裡的內部邏輯大概如下:
  判斷是否有候選詞,沒有的話就不用繪製。
  初始化背景的填充區域,直接view的背景中得到即可。
  對於每一個候選詞,得到其文字,然後計算其寬度,然後再加上兩邊的空隙。
  判斷是否選擇了當前詞:觸控的位置+滾動了的位置。如果是在當前詞的左邊到右邊之間,則將高亮區域繪製在畫布上面,高亮區域設定的大小即為當前詞的大小,並且儲存被選詞的索引。
  將文字繪製在這個候選詞的畫布上面,它進行了一個判斷,判斷哪個才是推薦詞。預設情況下是候選詞的第一個詞,但是它判斷第一個詞是否是合法的,如果是,則第一個詞是候選詞,否者第二個詞才是候選粗,然後進行繪製。
  繪製一條線,來分割各個候選詞。上面提到的總共的寬度在所有的詞都繪製出來之後,就能夠得到了。
  判斷目標滾動是否是當前的,不是就需要滾動過去。
  7. scrollToTarget,滾到到目標區域。得到當前值,然後加上一個滾動距離,看是否超過並進行相應調整,之後滾動到相應座標。
  8. setSuggestions,設定候選詞,之後進行繪製。
  9. onTouchEvent,觸控事件產生時呼叫。首先判斷是否為gesturedetector監聽的動作,如果不是就進行下面處理。初始化動作,把發生的動作記錄下來,點觸的座標也記錄下來。然後,根據動作型別分類反應:
  向下:沒動作;
  移動:如果是向左移動就要手動的選擇候選詞;
  向上:需要手動選擇候選詞。
  10. takeSuggestionAt,選擇在座標x處的詞,這個處理的是使用者輕輕點選鍵盤,也就是選擇候選詞。
  11. removeHighlight,去除高亮顯示。
  (五)SoftKeyboard.java
  整個輸入法的總體的框架,包括什麼時候建立,什麼時候顯示輸入法,和怎樣和文字框進行通訊等等。上面的檔案,都是為了這個類服務的。總體來說,一個輸入法需要的是一個輸入檢視,一個候選詞檢視,還有一個就是和應用程式的連結。
  基本時序圖如下:


  輸入法在Android中的本質就是一個Service,假設使用者剛剛啟動Android,使用者移動焦點首次進入文字編輯框時,Android便會通知Service開始進行初始化工作。於是便有了如圖中的一系列動作。
  追根溯源,onCreate方法繼承至Service類,其意義和其他Service的是一樣的。Sample在這裡,做了一些非UI方面的初始化,即字串變數詞彙分隔符的初始化。
  接下來執行onInitializeInterface,這裡是進行UI初始化的地方,建立以後和配置修改以後,都會呼叫這個方法。Sample在這裡對Keyboard進行了初始化,從XML檔案中讀取軟鍵盤資訊,封裝進Keyboard物件。
  第三個執行的就是onStartInput方法,在這裡,我們被繫結到了客戶端,接收所有關於編輯物件的詳細資訊。
  第四個執行的方法是onCreateInputView,在使用者輸入的區域要顯示時,這個方法由框架呼叫,輸入法首次顯示時,或者配置資訊改變時,該方法就會被執行。在該方法中,對inputview進行初始化:讀取佈局檔案資訊,設定onKeyboardActionListener,並初始設定 keyboard。
  第五個方法是onCreateCandidatesView,在要顯示候選詞彙的檢視時,由框架呼叫。和onCreateInputView類似。在這個方式中,對candidateview 進行初始化。
  第六個方法,也是最後一個方法,即onStartInputView,正是在這個方法中,將inputview和當前keyboard重新關聯起來。
  在上面的六個方法中,onCreateInputView和onCreateCandidatesView兩個方法只有在初始化時才會執行一次,除非有配置資訊發生改變。那麼究竟什麼是配置資訊發生改變呢?在看InputMethodService的API文件時,可以看到有一個方法onConfigurationChanged,根據文件解釋,這個方法主要負責配置更改的情況。在示例中,其沒有override這個方法,但是在android原始碼包中的PinyinIME中,有使用這個方法,有興趣的朋友可以在看完SoftKeyboard Sample之後,看看PinyinIME的原始碼。
  關於本類中其它的一些方法,由於比較直觀,就不進行講解了,感興趣的朋友可以參考《android sdk中 softkeyboard的自己解析(4)》。
  五、輸入法除錯
  通過使用除錯模式加斷點的方式,有助於我們更好的理解輸入法的時序和每個類及其方法的功能和呼叫持續。
  這裡使用Eclipse的DDMS透檢視進行除錯,具體介紹參考《用Eclipse開發和除錯Android應用程式》
  首先切換到DDMS模式,在這個模式下面,DDMS將連結到正在執行的手機或模擬器,並且能夠提取手機上面的各種資訊,比如執行緒,還有各個正在後臺執行的服務等等。點選工具條上的“Debug selected Process”,就能夠將偵錯程式植入到這個服務上面。


  之後切換到debug模式,就會發現偵錯程式已經連結到了這個模擬器,然後就可以像除錯普通的程式一樣除錯這個輸入法了。


  通過debug模式,我們可以發現,輸入法首先執行的onCreateInputView-> onCreateCandidatesView,而在這個時候,這個輸入法的介面一點兒都還沒有顯現出來。當我們在一個輸入框中點選滑鼠時,系統會產生一個事件,最開始就被輸入法捕獲,然後再將控制權交給這個輸入法。另外,切換物件的時候,輸入法總是認為是一次輸入的結束,然後進行一系列的reset工作。所有的鍵盤等事件,都會首先傳遞給輸入法,所以,如果一個按鍵事件不是我們所能夠處理的問題,我們需要將這個事件繼續傳遞下去,而不要丟棄了,因為這可能是別的控制元件的事情。
  在傳送訊息的介面,在輸入完TO某人之後,點選content輸入框,首先呼叫的是onFinishInput,也就是結束上一次的輸入,準備這次的輸入。之後呼叫的是onStartInputView,讓介面顯示出來。接著呼叫onStartInput,表示開始正式的輸入。在這過程中,要完成根據不同的輸入框,選擇不同的鍵盤,當你輸入一個鍵,首先觸發的是onKey回撥,在這裡要判斷是輸入的普通字元,還是控制性的字元,比如刪除,返回等等。比如這裡輸入一個 'g',然後會呼叫處理普通字元的函式handleCharacter。這裡的策略就是,輸入一個普通字元,就將Composing增加,並且更新這個候選詞的列表。這裡有一個很微妙的開關,就是mPrediction,它就是判斷是否是需要儲存這個Composing。在比如說URL框中輸入的時候,就會置這個開關為關,直接將鍵入的輸入到文字框中去。
  為了測試所有的函式,你必須想出一種輸入方式,讓每個函式你都能執行到,那你就能夠看清楚輸入法的本來面目。
  請各位朋友自己試試,對閱讀和理解原始碼的流程、時序和生命週期很有好處。也可以方便的找到自己的程式碼的bug。

  六、輸入法的呼叫
  希望從一個View上呼叫輸入法和接收輸入法傳過來的字串,可以通過呼叫EditText這個widget。但是,如果要做出很炫很個性的輸入法,就必須自己去和EditText一樣連線輸入法,介紹如下:
  首先,定義一個繼承自BaseInputConnection的類。前文提到過,輸入法是通過commitText來提交選中字元。
  public class MyBaseInputConnection extends BaseInputConnection{
  public MyBaseInputConnection(View targetView, boolean fullEditor) {
  super(targetView, fullEditor);
  }
  public static String tx="";
  //輸入法程式就是通過呼叫這個方法把最終結果輸出來的
  @Override
  public boolean commitText(CharSequence text, int newCursorPosition) {
  tx = text.toString();
  return true;
  }
  }
  BaseInputConnection相當於一個InputMethodService和View之間的一個通道。每當InputMethodService產生一個結果時,都會呼叫BaseInputConnection的commitText方法,把結果傳遞出來。
  之後,採用如下方式,撥出輸入法,並且把自定義的BaseInputConnection通道傳遞給InputMethodService。
  public class MyView extends XXView ...{
  //得到InputMethodManager
  InputMethodManager input = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
  //定義事件處理器
  ResultReceiver receiver = new ResultReceiver(new Handler() {
  public void handleMessage(Message msg) {
  }
  });
  ...
  //在你想撥出輸入法的時候,呼叫這一句
  input.showSoftInput(this, 0, mRR);
  ...
  @Override
  //這個方法繼承自View。把自定義的BaseInputConnection通道傳遞給InputMethodService
  public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
  return new MyBaseInputConnection(this, false);
  }
  }
  低階介面上面,自己呼叫輸入法並接收輸入法的輸出結果,就是這樣的。

  原文連結:http://www.cnblogs.com/weixing/archive/2013/09/04/3300947.html