2008年7月28日 星期一

在 Android 上利用 Google APIs 實現 Google Suggestion 功能

Using Google APIs to implement Google Suggest functions on Android platform.

這篇是屬於偏向教學性質的文章。在這篇,我將示範的是,如何利用 Google APIs,做出和 Google Suggest 一樣,會依照你輸入的部份字元,自動列出建議關鍵字的程式。這個程式的執行畫面,就像下面這樣。

在 Google 提供的眾多服務中,Google Suggest 是我自己很常用的功能之一,他可以幫我列出那些關鍵字是最常被使用的。如果你還沒用過,他的網址在這:http://www.google.com/webhp?complete=1&hl=zh-tw。你可以自己上去試用看看。

在開始介紹要如何寫出這樣一個程式之前,你會需要用到下面這些背景知識,我建議你要先讀過這些文章:

除了這些,在這篇教學中,你將會學到:

  • 如何用 HttpURLConnection 抓取網路服務所提供的資料。
  • 如何用 Handler 處理 Non-UI thread 的 UI 更新要求。
  • 如何用 Html.fromHtml() 在 TextView 上顯示簡單的 HTML 格式。

如何取得 Google Suggest 的建議關鍵字資料?

首先,要先知道如何取得這 Google Suggest 的建議關鍵字資料。要取得這建議關鍵字,你可以透過這個 URL,http://www.google.com/complete/search?xml=true&q=你的部份關鍵字字元。由於我們希望他傳回的是 XML 格式,因此在這個 URL 上要加上 xml=true這個查詢參數。例如 http://www.google.com/complete/search?xml=true&q=andr 這個 URL,所傳回的結果如下:

看到沒,這 suggestion data="android" 內的 data 資料,就是我們要的建議關鍵字。而 num_queries int="22500000" 內的 int 數目,則代表有多少和這個關鍵字相關的結果。

如何用 HttpURLConnection 抓取網路服務所提供的資料?

關於這 XML 格式的結果,待會我再說明,如何利用 DOM API,將我們要的資料抽取出來。我先說如何用 HttpURLConnection 去抓取這資料。先看下面這個程式片段:

在第 10~11 行中,我們先利用 URLEncoder.encode() 產生包含查詢字串的完整 URL 地址,並產生個 URL 物件。在 14 行中,用 URL.openConnection(),打開一個 HttpURLConnection 連結物件。有了這個物件,接著的 getResponseCode(),就會實際連到你所指定的網址,並將你所指定的頁面資料傳回來。這傳回的資料,就在第 19 行 http.getInputStream() 所傳回的 InputStream 內。最後的第 21~24 行,就是在將這傳回的 XML 資料,轉成 Document 物件。之後,我們就可以用 DOM APIs,抽出我們要的資料。

如何解析 XML 資料並轉成 DOM?

底下的程式片段說明如何用 DOM APIs,抽出我們要的建議關鍵字及其結果數量。

所有抽出來的建議關鍵字其數量值,都放在 alSuggWord 和 alSuggVal 這兩個 ArrayList 中。底下的程式,則是簡單地依照數量值重新排序最後的結果。我們要的,當然是數量最多的排第一。

如何客製化 AutoCompleteTextView 中的 Filter 功能?

我們知道,每當你在 AutoCompleteTextView 中輸入一個字元,他都會呼叫 Filter 類別的 performFiltering() 函式,讓你自己過濾所要顯示的結果。由於我們希望所有的結果,都是透過 Google Suggest API 所要回來的。因此我們在這個函式中,主要就是呼叫前面介紹過的 GoogleSuggestiong.Get() 取得所有的建議關鍵字。

如何用 Handler 處理 Non-UI thread 的 UI 更新要求?

在大多數的 single thread GUI framework 上,都會規定你不能在這個寶貴的 UI thread 中,花太長的時間來執行某段程式處理,Android 也是如此。如果你真的違反這個規定,那你的使用者就會看見 ANR (Application is Not Responding) 這個警告訊息。

這個的解法就是將原先要花許多時間處理的程式移到另一個 non-UI thread 上。

不過,另外一個問題來了。在 Android 中,只有 UI thread 可以呼叫 UI 物件所提供的函式。例如,在這個範例中,在取得建議關鍵字的過程中,我們都會呼叫 _UpdateStatus(),顯示目前的進度狀態。不過由於 Filter.performFiltering() 在 Android 的設計上,他是被另一個 Non-UI thread 所呼叫的。因此在 _UpdateStatus() 中,你可不可以直接呼叫 TextView 的 setText() 函式。我的解法就是在 Non-UI thread 中,透過 Handler,傳送一個 message 到 UI thread 的 handler 處理函式,讓 UI thread 來處理 View 類別的相關顯示工作。底下是關於這個處理的程式片段:

如何用 Html.fromHtml() 在 TextView 上顯示簡單的 HTML 格式?

TextView 其實提供了許多好用的功能,其中最棒的是,他還允許你顯示簡單的 HTML 格式。你只要傳個 Spanned 物件給 setText() 即可。在 Android 上,有許多 APIs 都可以幫助你產生,Spanned 物件,不過我最常用的就是 Html.fromHtml(),原因就是他簡單好用。看了底下的程式片段,你應該就會用了。

最後,底下是關於 sugg.xml 檔的內容。

這個範例程式,只做到列出候選的建議關鍵字讓你選。至於 action 函式,就請你發揮自己的創意繼續完成他囉。

3 則留言:

elbe 提到...

請問你有試過只輸一個字如a,是否會出現結果

samlu 提到...

至少要輸入幾個字才啟動 auto-complete 機制,是可以自己設定的。
Please check AutoCompleteTextView::setThreshold(int threshold) method.

Specifies the minimum number of characters the user has to type in the edit box before the drop down list is shown.

Unknown 提到...

不好意思,我發現現在輸入網址已經不會回傳num_queries筆數了
是不是google本來就沒打算公開此資訊嗎?

張貼留言