Content Providerは、アプリケーション間でデータにアクセスするための統一インターフェースを提供するAndroidコンポーネントです。物理ストレージ(SQLite、ファイル、ネットワークソース)を抽象化し、ContentResolverを介して安全な情報交換を実現します。Android Developer Guide, 2026によると、Content ProviderはActivity、Service、BroadcastReceiverと並ぶAndroidアプリケーションの4つの主要コンポーネントの1つです。その役割は、読み取りおよび書き込み権限の制御を通じて、他のアプリケーションがデータを利用できるようにすることです。
重要なポイント
Content Providerは、中央集権型データストアへのアクセスを管理し、統一された契約インターフェースを通じて他のアプリケーションにデータを提供するAndroidコンポーネントです。ストレージの実装詳細を隠蔽します。データはSQLite、ファイルシステム、クラウドに保存することも、ネットワークリクエストの結果とすることもできます。
Androidにはシステムデータ用の組み込みContent Providersが含まれています — ContactsContract、MediaStore、CalendarContract、CallLogなどです。サードパーティアプリケーションも、安全なデータ交換のために独自のプロバイダーを作成できます。各プロバイダーは、URIの最初の部分を形成する一意の文字列であるauthorityとともにAndroidManifest.xmlに登録されます。
Content Providerはクライアント-サーバーモデルで動作します。プロバイダーは、query、insert、update、delete、getType、onCreateの6つの必須メソッドを実装するサーバーとして機能します。クライアント(別のアプリケーション)はContentResolverを介してプロバイダーにアクセスし、ContentResolverはAndroidのIPCメカニズムを通じて呼び出しをプロバイダーの対応するメソッドに変換します。
各Content Providerはcontent://スキームのURIで識別されます。例:content://com.example.app.provider/items。最初の部分authority(com.example.app.provider)はマニフェストでプロバイダークラスにバインドされます。パス/itemsはテーブルを指し、/items/5はID=5の特定のレコードを指します。
アプリケーションがContentResolver.query(URI)を呼び出すと、Androidは呼び出し元パッケージの権限を確認し、authorityによってプロバイダーを見つけ、まだ実行されていなければそのプロセスを開始します。プロバイダーはクエリを実行し、結果を含むCursorオブジェクトを返します。これによりクライアントはレコードを反復処理できます。
ContentProviderクラスでは6つの抽象メソッドの実装が必要です。各メソッドはURIを受け取り、操作の種類に対応する結果を返します。システムは任意のプロセスからこれらのメソッドを呼び出すため、スレッドセーフであり、長時間実行をブロックしないようにする必要があります。
queryメソッドは、URI、カラムのprojection配列、引数付きのselection文字列、ソート順を受け取ります。データを含むCursorを返します。実装では、UriMatcherを使用してURIを解析し、データベースに対して対応するSQLクエリを実行する必要があります。
これらのメソッドはストア内のデータを変更します。insertはContentValues(キーと値のペア)を受け取り、新しいレコードのURIを返します。updateとdeleteはレコードをフィルタリングするためのselectionを受け取り、影響を受けた行数を返します。データ変更後、プロバイダーはContentResolver.notifyChangeを通じて通知する必要があります。
| メソッド | 目的 | 戻り値 |
|---|---|---|
| query | URIによるデータ取得 | Cursorまたはnull |
| insert | 新しいレコードの追加 | 新規レコードのURI |
| update | 既存レコードの更新 | int(行数) |
| delete | レコードの削除 | int(行数) |
| getType | URIのMIMEタイプ | String |
| onCreate | プロバイダーの初期化 | boolean |
ContentResolverは、システム内のすべてのContent Providersを操作するための単一のアクセスポイントです。クライアントアプリケーションはプロバイダーのメソッドを直接呼び出すことはなく、常にContentResolverを介して呼び出します。ContentResolverはAndroidがコンテキストから取得します。ContentResolverのCRUD操作はプロバイダーと同じ名前ですが、直接参照ではなくURIを受け取ります。
プロバイダー内で受信URIを解析するためにUriMatcherが使用されます。URIを数値コードにマッピングできます。たとえば、URI content://authority/itemsはコード1、content://authority/items/#はコード2になります。これにより、各メソッドでの手動のURI文字列解析が不要になります。
// ContentResolverを使用して連絡先にアクセスする
val uri = ContactsContract.Contacts.CONTENT_URI
val cursor = contentResolver.query(
uri,
arrayOf(ContactsContract.Contacts.DISPLAY_NAME),
null, null, null
)
cursor?.use {
while (it.moveToNext()) {
val name = it.getString(it.getColumnIndexOrThrow(
ContactsContract.Contacts.DISPLAY_NAME
))
Log.d("連絡先", "名前: $name")
}
}
Cursorは使用後必ず閉じる必要があります — 上記の例ではuse関数(Kotlin拡張)がこれを行います。Cursorを閉じないと、Binderプール内のデータへの参照を保持するためメモリリークが発生します。UIシナリオでは、LiveData/FlowとともにCursorLoaderまたはRoomを使用してください。
独自のContent Providerを作成するには、ContentProviderクラスを拡張することから始めます。プロバイダーはSQLiteOpenHelperを介してSQLiteデータベースと連携し、UriMatcherを使用してクエリタイプを決定します。ノートリストを管理するための最小限の実装を考えてみましょう。
プロバイダーはAndroidManifest.xmlのapplicationタグ内に登録します。authorities属性は一意の識別子を設定し、exportedは他のアプリケーションがプロバイダーにアクセスできるかどうかを決定します。exported=trueがない場合、プロバイダーはアプリケーション内からのみアクセス可能です。
// ノート用のContent Providerの例
class NotesProvider : ContentProvider() {
companion object {
const val AUTHORITY = "com.example.app.notes"
const val NOTES_PATH = "notes"
const val NOTES_URI = "content://$AUTHORITY/$NOTES_PATH"
const val NOTES_ID = "content://$AUTHORITY/$NOTES_PATH/#"
private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
addURI(AUTHORITY, NOTES_PATH, 1)
addURI(AUTHORITY, "$NOTES_PATH/#", 2)
}
}
override fun query(uri: Uri, projection: Array<String>?,
selection: String?, args: Array<String>?, sort: String?): Cursor? {
return when (uriMatcher.match(uri)) {
1 -> dbHelper.readableDatabase.query(TABLE_NOTES,
projection, selection, args, null, null, sort)
2 -> dbHelper.readableDatabase.query(TABLE_NOTES,
projection, "_id=?", arrayOf(uri.lastPathSegment), null, null, null)
else -> throw IllegalArgumentException("Unknown URI: $uri")
}
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
val id = dbHelper.writableDatabase.insert(TABLE_NOTES, null, values)
context?.contentResolver?.notifyChange(uri, null)
return ContentUris.withAppendedId(uri, id)
}
override fun delete(uri: Uri, selection: String?, args: Array<String>?): Int {
val count = dbHelper.writableDatabase.delete(TABLE_NOTES, selection, args)
context?.contentResolver?.notifyChange(uri, null)
return count
}
// getType、update、onCreateは省略
}
プロバイダークラスを作成したら、android:authoritiesおよびandroid:exported属性(プロバイダーが公開の場合はtrue)を指定してマニフェストに登録する必要があります。システムは最初のアクセス時にプロバイダーのインスタンスを作成します。これはUIスレッドで発生するため、onCreateは迅速に実行される必要があります。
Content Providerは、読み取り権限と書き込み権限の2つのレベルでデータアクセスを管理できます。これらはマニフェストでandroid:readPermission属性およびandroid:writePermission属性で設定します。クライアントアプリケーションに対応する権限がない場合、システムはSecurityExceptionで呼び出しを拒否します。
AndroidはFLAG_GRANT_READ_URI_PERMISSIONフラグとFLAG_GRANT_WRITE_URI_PERMISSIONフラグによる一時的な権限をサポートしています。これは、アプリケーションがIntentを介して別のアプリケーションにファイルURIを渡す場合に便利です。受信側は特定のURIにのみ制限時間内でアクセスできます。システムは受信側アプリケーションの終了後に一時的な権限を取り消します。
システムプロバイダーについては、Androidはアプリケーションのマニフェストで特定の権限を指定する必要があります。たとえば、連絡先にアクセスするにはREAD_CONTACTS、カレンダーにアクセスするにはREAD_CALENDARが必要です。Android 6以降、これらの権限はインストール時ではなく実行時に要求されます。
よくある質問
Content Providerは、ContentResolverを介したアプリケーション間のデータ交換のための標準インターフェースを提供するAndroidコンポーネントです。ストレージ方式(SQLite、ファイル、ネットワーク)を抽象化し、読み取りおよび書き込み権限制御により安全なデータアクセスを保証します。
Authorityは、AndroidManifest.xmlで指定されるプロバイダーの一意の識別子文字列です。URI content://authority/pathの最初の部分を形成し、システムがContentResolverの呼び出しを正しいプロバイダーにルーティングするために使用します。Authorityはデバイス上のすべてのアプリケーション間で一意である必要があります。
UriMatcherはURIを数値コードにマッピングします。addURIを使用してパターンを追加し、matchを呼び出して受信URIのコードを取得します。これにより、query、insert、update、deleteメソッドがどのテーブルまたはレコードが要求されているかを判断し、データベースで対応する操作を実行できます。
はい、Cursorは使用後必ず閉じる必要があります。Cursorを閉じないと、プロバイダーのデータへのBinder参照を保持するためメモリリークが発生します。Kotlinでは自動クローズにuse関数を使用し、Javaではtry-with-resourcesまたはfinallyブロックでcursor.close()を使用してください。
Content Providerはアプリケーション間のデータアクセスのためのコンポーネントであり、SQLiteDatabaseは単一アプリケーションの内部ストレージメカニズムです。Content ProviderはURIインターフェースと権限制御を提供する一方、SQLiteDatabaseはOSレベルのセキュリティメカニズムなしでデータベースを直接操作します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。