iT邦幫忙

2025 iThome 鐵人賽

DAY 26
0

ContentProvider 與資料共享機制

intro

在 Android 系統中,應用程式之間通常彼此隔離,預設情況下無法直接存取對方的資料。
但有時候,應用之間需要安全且有規範地共享資料,例如:

  • 通訊錄 App 要讓其他 App 查詢聯絡人資料
  • 相簿 App 要讓社群 App 取得圖片
  • 系統設定 App 要讓第三方修改部分參數

為了解決這個跨應用資料存取的需求,Android 提供了 ContentProvider 機制。

ContentProvider 是 Android 四大元件之一,負責「封裝資料並提供統一介面進行 CRUD 操作(Create、Read、Update、Delete)」。
它讓不同應用之間能透過 URI(Uniform Resource Identifier) 安全地交換資料。

ContentProvider 在 Android 架構中的位置

ContentProvider 位於 Android Framework 的 Application 層與 Binder IPC 橋接層之間,屬於 應用層資料共享框架。

+-----------------------------------------------------+
|                   Application 層                    |
|  (App A)                (App B)                     |
|  ┌─────────────────┐   ┌─────────────────────┐      |
|  |  ContentProvider│   |  ContentResolver    │      |
|  └────────┬────────┘   └────────┬────────────┘      |
|           │                     │                   |
|           ▼                     ▼                   |
|           <------ Binder IPC 通信層 ------>          |
|                     (ActivityManagerService 等)     |
+-----------------------------------------------------+
|                   Native 層 & Kernel                |
+-----------------------------------------------------+
  • App A(資料提供者)透過 ContentProvider 對外暴露資料存取介面,
  • App B(資料使用者)透過 ContentResolver 以 URI 方式請求資料,
  • 中間的 IPC 橋接由 Binder 機制 與 ActivityManagerService 協調完成。

ContentProvider 的主要組成與職責

元件 說明
ContentProvider 定義資料表結構、URI、以及 CRUD 操作邏輯。
ContentResolver 提供統一的 API 讓其他 App 查詢資料(query、insert、update、delete)。
UriMatcher 用來解析傳入的 URI 並對應到具體的資料操作。
ContentObserver 觀察資料變化事件(例如資料庫更新時通知 UI)。
Permission 管控 透過 AndroidManifest.xml 指定 android:readPermission、android:writePermission 進行授權控制。

###URI 與資料定位
ContentProvider 使用 URI 來標識資料來源。
URI 格式如下:
content://<authority>/<path>/<id>
例如:
content://com.android.contacts/contacts/5
代表:

  • authority:提供者的名稱(如 com.android.contacts)
  • path:資料路徑(如 contacts)
  • id:具體的資料項目(如 ID=5)
    每一個 URI 都對應到 ContentProvider 中的特定資料表或資料項。

ContentProvider 的生命週期與啟動流程

(1) 啟動流程概觀

  1. App B 透過 ContentResolver 呼叫 query()。
  2. 系統檢查目標 URI 所屬的 authority。
  3. AMS(ActivityManagerService)確認對應的 ContentProvider 是否已啟動:
  • 若尚未啟動,則透過 Zygote fork 啟動 App A(資料提供者)。
  1. AMS 通知 App A 的 ActivityThread 建立對應的 ContentProvider 實例。
  2. App B 取得該 ContentProvider 的 Binder 代理,完成 IPC 溝通。
App B                         AMS                       App A
 │  query()                    │                         │
 │ ───────────────────────────▶│                         │
 │                             │──檢查Provider是否已啟動──▶
 │                             │                         │──建立Provider實例──▶
 │                             │◀────註冊Provider Binder──│
 │◀────────返回Proxy────────────│                         │
 │──透過Binder呼叫query()──────▶│                         │
 │◀────────回傳Cursor───────────│                         │

CRUD 操作流程

ContentProvider 定義五個核心介面方法:

方法 功能 範例
query() 查詢資料 resolver.query(uri, projection, ...)
insert() 新增資料 resolver.insert(uri, values)
update() 更新資料 resolver.update(uri, values, ...)
delete() 刪除資料 resolver.delete(uri, ...)
getType() 回傳 MIME 類型 vnd.android.cursor.dir/vnd.<authority>.<path>

Ex. 查詢聯絡人

val uri = Uri.parse("content://com.android.contacts/contacts")
val cursor = contentResolver.query(uri, null, null, null, null)

while (cursor?.moveToNext() == true) {
    val name = cursor.getString(cursor.getColumnIndex("display_name"))
    Log.d("Contact", name)
}
cursor?.close()

安全性與權限機制

為了防止惡意 App 存取敏感資料,ContentProvider 提供多層安全防護:

  1. 宣告權限
    在 AndroidManifest.xml 中設定:
<provider
    android:name=".ContactsProvider"
    android:authorities="com.example.contacts"
    android:readPermission="com.example.permission.READ_CONTACTS"
    android:writePermission="com.example.permission.WRITE_CONTACTS" />
  1. URI 限制
  • 僅對特定 URI 路徑授權(可結合 UriPermission)。
  1. 臨時權限授與
  • 透過 Intent 的 FLAG_GRANT_READ_URI_PERMISSION 允許短期資料分享,例如拍照後傳遞圖片 URI。
  1. 跨用戶存取控制(多使用者環境)
  • AMS 會驗證呼叫者 UID,確保同一裝置的不同使用者空間隔離。

ContentObserver:資料變化監聽

當資料透過 ContentProvider 更新時,可通知相關 UI 或服務更新畫面。

contentResolver.registerContentObserver(
    Uri.parse("content://com.example.provider/items"),
    true,
    object : ContentObserver(Handler(Looper.getMainLooper())) {
        override fun onChange(selfChange: Boolean) {
            Log.d("Observer", "資料已更新!")
        }
    }
)

當 insert()、update()、或 delete() 被呼叫後,可觸發:
context.contentResolver.notifyChange(uri, null)

與 SQLite 的關係

雖然 ContentProvider 常以 SQLite 資料庫為底層存儲介質,但它並不限定必須使用 SQLite。
底層可對應:

  • SQLite 資料庫(最常見)
  • File System
  • Network API
  • SharedPreferences
    透過 ContentProvider,這些資料來源都能以統一的 URI 介面對外提供服務。

實際應用案例

  1. 系統內建 Provider
Provider 名稱 Authority 功能
ContactsProvider com.android.contacts 聯絡人資料
MediaStore media 媒體檔案 (照片、影片、音訊)
SettingsProvider settings 系統設定項目
DownloadsProvider downloads 檔案下載紀錄
  1. 自訂 Provider 範例
    開發者可建立自訂 Provider,例如:
class NoteProvider : ContentProvider() {
    override fun onCreate(): Boolean {
        dbHelper = NotesDbHelper(context)
        return true
    }
    override fun query(...) = db.query("notes", ...)
    override fun insert(...) = db.insert("notes", null, values)
    override fun update(...) = db.update("notes", values, where, args)
    override fun delete(...) = db.delete("notes", where, args)
}

效能與最佳化

  • 避免頻繁 Query
    • 使用批次查詢或 Cache。
  • 使用 CursorLoader 或 LiveData
    • 搭配 Lifecycle 感知元件。
  • URI 精細化設計
    • 將多表資料以 path 區分,減少不必要的 join。
  • 僅在必要時暴露 Provider
    • 若僅供內部使用,設定 android:exported="false"。

架構整合:ContentProvider 在系統中的角色

ContentProvider 不僅是 App 之間共享資料的介面,也被 Android Framework 廣泛使用:

  • SettingsProvider → 系統設定存取
  • DownloadsProvider → 檔案管理與 DownloadManager
  • MediaStoreProvider → 圖片、音樂、影片管理
  • TelephonyProvider → 簡訊與通話紀錄管理
    這些 Provider 都透過 Binder 與 AMS 協作,形成 Android 資料交換的基石。

Summary

特性 說明
主要功能 在不同應用間安全共享資料
通訊機制 透過 Binder IPC
資料識別 使用 content URI
權限控制 支援 read/write 權限與臨時授權
常見用途 聯絡人、媒體庫、設定、下載紀錄等
替代技術 若僅限 App 內部共享,可使用 Room、Repository、或 Jetpack DataStore
   +-----------------+             +----------------------+
   |   App A (Provider) |          |   App B (Client)    |
   |  ┌───────────────┐ |          |  ┌───────────────┐ |
   |  | ContentProvider│◄──────────┤  | ContentResolver│ |
   |  └──────┬────────┘ |          |  └───────────────┘ |
   |         │           |          |                    |
   |   SQLite/Files/API  |          |                    |
   +---------------------+          +----------------------+
                ▲
                │
       notifyChange() → ContentObserver

ContentProvider 是跨應用資料共享的核心機制

  • 使用 URI 標識資料來源
  • 通過 Binder 進行 IPC 通信
  • 具備完整的權限與通知機制
  • 為系統多項服務(如 Contacts、MediaStore)提供底層支持

上一篇
#24
系列文
安豬複習26
  1. 22
    #21
  2. 23
    #22
  3. 24
    #23
  4. 25
    #24
  5. 26
    #25
完整目錄
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言