2010年6月22日 星期二

Android 原始碼徹底研究系列 - 鬧鐘程式, ContentProvider (5)

Android Source Code Internals - Alarm Clock, ContentProvider (5)

這一系列的 鬧鐘應用原始碼的剖析研究,這一篇應該是壓軸了。在這鬧鐘應用原始碼系列研究的最後,要和大家介紹的是,在鬧鐘應用中如何建立與使用 ContentProvider 這個元件。

剛學 Android 的人,應該都看過這個關於 Android 4 大元件 的相關文件。從這個文件中,我們知道這 4 大元件,分別是 Activities, Services, Broadcast receivers 和 Content providers。在程式中,只要你有用到這 4 大元件,都必須要在 AndroidManifest.xml 中宣告。從鬧鐘應用的 AndroidManifest.xml 內容來看,除了 Service 之外,他涵蓋了其他三大 Android 元件,這也是為何我先挑他出來介紹的主要原因之一。

因此,依照慣例,我們先打開 AlarmClock 的 AndroidManifest.xml 檔案,你會看到 #13 有宣告 AlarmProvider 這個 content provider。

如果你對甚麼是 ContentProvider 還不了解的話,建議你一定要先看看下列文章:

為了資料的隱密與保護性,在 Android 中,各個應用程式所儲存的資料,都在自己的保護區內。就算你知道他的檔案名稱與路徑,你也會因為權限的關係,無法存取別人的資料。這樣的作法,資料保護的目的性是達到了,可是卻犧牲了合作性。怎麼說?例如,在手機上,所有聯絡人的資料,都是由聯絡人這個應用所創建與管理的。如果你想寫個寄信程式,並且想讓使用者從現有的聯絡人中,挑選 email 地址。好了,這問題來了,這聯絡人的資料是由另一個應用所掌管的,你的應用想要存取別的應用所掌管的資料,看來是行不通的。在 Android 上,這樣的功能,應該怎麼做?

為了解決這資料互通的需求,Android 提出了 ContentProvider。簡單地說,ContentProvider 的出現,就是要讓某個應用所儲存的資料,可以被其他應用所讀取或寫入。而且 ContentProvider 本身還提供了權限管理的機制,讓只有獲得授權的第三方應用,可以透過他來存取資料。

ContentProvider 並沒有規定後台的資料儲存媒介。你可以用 SQL 資料庫,當然也可以用檔案,或其他你方便使用的方式。因此,規定一個統一存取的介面是必要的。ContentProvider 為這統一的存取介面,定義了以 URI 為基礎的 REST 存取方式。而所有要透過 ContentProvider 存取資料的應用,都必須要先透過 ContentResolver,幫你找到適合的 ContentProvider 才行。

最上面那個圖,就是鬧鐘應用中,和 ContentProvider 相關的方塊圖。鬧鐘應用將使用者所設定的所有鬧鈴,都儲存在一個 SQLite 資料庫 (alarms.db) 中。為了讓自己與其他應用也可存取這鬧鈴設定,AlarmProvider.java 是 ContentProvider 的實作,並提供底下兩種 REST 存取 APIs。

例如,處理這兩個 REST APIs 的查詢關鍵地方就在:

要實作出一個 ContentProvider,除了要自行定義可供外部使用的 REST APIs 外,你還要定義底下函式:

關於這些函式的實作細節,就請你就自行參閱 AlarmProvider.java

好了,你已經看到鬧鐘應用如何實作 ContentProvider,以及他所提供出來的 APIs。接下來,我們來看看要如何透過 ContentProvider,來存取這些鬧鈴設定。

在鬧鐘應用中,所有和 ContentProvider 相關的存取,都在 Alarms.java 中。

我們來看殺掉鬧鈴設定的功能是如何實現的:

看到這,我們可以了解,即使要在自己的應用中殺掉 ID 為 5 的鬧鈴設定,你只要用底下方式呼叫即可:

在鬧鐘應用中,看似提供 ContentProvdier 這樣的介面是多餘的,畢竟只有他自己一個人在用。不過,在 Android 中,強調的是大家分工合作,透過 Intent 及 ContentProvdier 的機制,讓各個應用程式之間,能更完美無縫地的整合在一起。因此在知道鬧鐘應用的 ContentProvdier 介面後,如果日後你想在你的程式中,加上增減鬧鈴的功能,你就不用自己做了,完全可以透過現有的鬧鐘應用來完成,這樣的模式對使用者也好。反過來想,如果你的應用也能提供 Intent 與 ContentProvider 的話,這樣是不是也能讓別人和你更容易地整合在一起呢?

沒有留言:

張貼留言