顯示具有 Filterable 標籤的文章。 顯示所有文章
顯示具有 Filterable 標籤的文章。 顯示所有文章

2008年12月15日 星期一

如何在 ListView 上加上按鍵過濾的功能

How to add type filter functionality for your ListView widgets?

由於手機螢幕的大小有限,為了要顯示更多的資料,ListView 通常是首選元件。因此,在各式的應用程式中,幾乎都可以見到他的身影。ListView 不只好用,ListView 也提供了各式各樣的客製化功能。我想,他可算是 Android 中,功能最為複雜的元件之一。

今天要分享給大家的,就是如何在 ListView 中 加上按鍵過濾的功能。

想要知道什麼是『按鍵過濾』?想想,當你有上百個聯絡人時,如何快速地找到一個叫 Sam 的人?要知道答案,執行 Contacts 這個程式,按下 's' 鍵,這時你會發現只剩 s 開頭的聯絡人,再按下 a 鍵,幾乎答案就呼之欲出了,因為以 sa 開頭的聯絡人,只剩屈指可數的數目。這種依照你按鍵輸入的文字,來過濾 ListView 所要顯示的內容,就是我這提的『按鍵過濾』功能。

要如何做到這功能?為了要找到解法,我開始翻出 Contacts 的原始碼,仔細研究他是如何做到的。在研讀原始碼的過程中,還意外發現其中還藏了 Android Secret Code 這個東西。試試,在你的 G1 手機上,輸入 *#*#4636#*#* 。嘿嘿,你看到什麼了嗎?用模擬器,是沒用的,一定要實體手機才行。還有更多的 secret code ,我貼在 Android secret code 這篇文章上。有興趣的,自己上去瞧瞧。

好了,言歸正傳。關於要如何做到『按鍵過濾』功能的答案,其實非常簡單,就是對你的 ListView 加上 setTextFilterEnabled(true) ,就可以了。

對你的程式沒效嗎?先別急,這還有個但書,那就是你透過 ListView.setAdapter() 所傳入的 ListAdapter, 一定要實現 Filterable 這個介面才行。目前,ArrayAdapter,CursorAdapter 和 SimpleAdapter 這幾個 Adapter 都有實現 Filterable 這個介面。一般大家常用的是 ArrayAdapter<String> ,那你只要對你的 ListView 加上 setTextFilterEnabled(true) ,應該馬上就有『按鍵過濾』的功能。在 API Demos 程式中,第一個畫面內的 ListView 也有加上這功能。

不過,通常事情都沒這麼簡單。像我的 ListAdapter 就是繼承自 BaseAdapter,做出自己的 Adapter。BaseAdapter 當然沒有實現 Filterable 這個介面。你得自行實現 Filterable 介面所要求的 performFiltering() 和 publishResults() 函式。

如何實現這兩個函式?我在 在 Android 上利用 Google APIs 實現 Google Suggestion 功能 這篇文章中,有提到過。

另外,別忘了,你還有 Android 原始碼可以參考,那是你最好的導師。為了幫助你的了解,我將 platform\framework\base\core\java\android\widget\ArrayAdapter.java 原始碼中,關於如何實現 Filterable 介面的部份,貼出來,分享給你。


繼續閱讀全文...

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 函式,就請你發揮自己的創意繼續完成他囉。


繼續閱讀全文...

2008年7月7日 星期一

客製化 AutoCompleteTextView 中的 Filter 功能

How to customize the filtering function for AutoCompleteTextView widget?

這裡 我提過,另一個縮小 AutoCompleteTextView 的方法,就是自己寫個 ArrayAdapter,然後在 getView() 中,產生個 TextView 給 AutoCompleteTextView。這簡單的程式片段,大致如下。在 getView() 函式中,自己 new 個 TextView widget。

不過,要寫個可以給 AutoCompleteTextView 用的 ArrayAdapter,可沒表面上看起來那麼地簡單。因為,你還要在這個類別裡,寫個 Filterable 介面的實現才行。

這個 Filterable interface 就是用來,從現有的全部結果中,依照你輸入的字元,過濾出符合的結果。而 AutoCompleteTextView ,則只單純地列出 Filterable 所傳回的結果。例如,當你輸入個 B 字元時,AutoCompleteTextView 就藉由 Filterable 的函式,列出只有 B 開頭的國家。這也是 AutoCompleteTextView 中,最主要的功能。

不過,如果你想要列出所有的國家,AutoCompleteTextView 目前可沒這樣的功能。最簡單的方式,就是自己寫個 Filterable 的實現。所以啦,Filterable 可不是只能用來過濾結果。你可拿它來做任何事,AutoCompleteTextView 根本不管他傳回的內容是什麼,他只單純地列出 Filterable 所傳回的結果。

延續 這裡 的例子,我將他改成,如果只輸入 "*" 這個字元,就列出所有的國家。如果是其他字元,就依照原先的用法,列出符合輸入字元的國家。

在 Filterable 這個介面中,你要實現這兩個方法。

底下就是,如何在這兩個函式中,實現用 "*" 列出所有國家。

還沒完,接下來,你還要在你自己的 ArrayAdapter (這裡的 CntyListAdapter),實現下列的方法才行。

好了,最後的執行結果就像這樣。你想到要利用 Filterable ,來做出什麼特別功能嗎?


繼續閱讀全文...