ContentProviderとは
ContentProviderはデバイスのストレージにあるDB(データーベース)にアクセスし、データを管理する為に使用されます。具体的には、自身のアプリでDBを使ったり、他アプリのDB(連絡先など)を流用したい時です。今となっては他のアプリと連携させたアプリなど往々にして存在しますが、そのような機能の一端を担えるのがこのContentProviderです。 ContentProviderを導入するか否かの指針については公式のドキュメントに記述があります。以下がその項目です。
・検索フレームワークを用いてカスタム検索候補を提供する。
・アプリデータをウィジェットに公開する
・他のアプリに複雑なデータやファイルを提供する。
・AbstractThreadedSyncAdapterクラス(デバイスとサーバとの間でデータを転送するタスクのコードのカプセル化に使う)、CoursorAdapter(カーソルとビューの架け橋を担う)、CorsorLoader(カーソルからデータを取得する)を使う。
これらの項目に当てはまる状況の時、ContentProviderが推奨されているようです。
ContentProviderクラス
ContentProviderを実際に使うには、ContentProviderクラスを実装したクラスを用意することが必要です。そのインスタンスは様々な処理を経て、デバイスのデータへアクセスすることが可能になります。その際に用いられるメソッドとして、6つの必須メソッドが存在します。以下でそのそれぞれについて解説していきます。
query()
このメソッドはプロバイダからデータを取得する際に使用されます。実装すると以下のようになるはずです。
override fun query(
uri: Uri,
projection: Array<out String>?,
selection: String?,
selectionArgs: Array<out String>?,
sortOrder: String?
): Cursor? {
}
引数それぞれについて解説していきます。uri
はqueryメソッドを使って取り出したいデータがあるデータベースのURIです。具体的には、content://パッケージ名.provider/テーブル名
で該当するテーブルに、content://パッケージ名.provider/テーブル名/ID
で該当するテーブルの該当するIDを持つ行にアクセスすることが出来ます。projection
は対象とするテーブルのカラム名を持つ文字列配列で、queryはここで指定したカラムのデータのみを取得します。selection
はSQLのWHERE文における、WHERE =
に続く文字列を渡してあげることで、テーブルに対してWHERE文を使ってデータの選択を行うことが出来ます。selectionArgs
もselection
と同じ類のものですが、SQLインジェクションを防ぐためのもので、selection
と連携して使います。本筋とはズレてしまうので、詳しい説明は割愛で。setOrder
は取得したデータにおける行の順番を入れ替えることが出来ます。ORDER BY
に相当する指定を行うことが可能で、例えばCOLUMN_NAME ASC
という文字列を渡したとすると、返ってくるデータはCOLUMN_NAME
というカラムが昇順になるよう順番が入れ替えられます。
このメソッドの返り値はCursor
オブジェクトです。
insert()
このメソッドはプロバイダに対して新しい行を挿入する時に使われます。非常にシンプルに扱うことが出来ます。
override fun insert(uri: Uri, values: ContentValues?): Uri? {}
uri
はquery
と同じく、データを挿入したいテーブルのURIを渡してあげます。value
はContentValues
のオブジェクトで、データベースに挿入したいデータをカラムの名前とデータのペアで保持します。ContentValues
がNullableなように、この値はnullになることが可能です。
返り値は新しく挿入されたアイテムのURIです。具体的には、先ほど説明した末尾がIDのタイプのURIです。もしデータの挿入が上手く行かなかったら、この値はnullになります。
update()
このメソッドはプロパイダ内の既存の行を更新します。引数で更新する行の細かな指定が可能です。
override fun update(
uri: Uri,
values: ContentValues?,
selection: String?,
selectionArgs: Array<out String>?
): Int {
引数はほぼほぼquery
メソッドと同じです。唯一異なるのはvalues
がある点です。しかし、values
に関してはinsert
メソッドで説明したものと大体同じで、更新に使われるデータを渡します。
返り値は実際に更新した行の数をInt型で渡してくれます。
delete()
プロパイダから行を削除する為に使用されます。
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int
引数や返り値に関してはupdate
メソッドとほぼ同じです。value
が引数にない点だけ異なります。
getType()
与えられたURIに対するMIMEタイプを返します。
override fun getType(uri: Uri): String?
MIMEタイプとは、拡張子と対になるような概念で、.pngというファイルならimage/pngというMIMEタイプを持ち、データの種類を表してくれます。どのような場面で必要になるかというと、ContentProvider
を通してやり取りを行うデータに画像や文字列が混在する時、このメソッドを用いてそのそれぞれの処理を分けることが可能です。返り値は先述したように、MIMEタイプを文字列で返してくれます。
onCreate()
プロパイダを初期化するメソッドです。プロバイダが作成された時、Androidシステムがこのメソッドを即座に呼び出してくれます。
override fun onCreate(): Boolean {
Log.d(TAG, "onCreate: starts")
return true
}
このメソッドはデータベースとやり取りを行ったり、ユーザーに何かを提供したりといった事はありません。リファレンスに極力冗長にならないようにと書かれているように、不用意にコードを書くとプロバイダの起動が遅くなってしまいます。返り値はtrueを返せば正常に動作します。
ContentResolver
ContentProvider
を実装したクラスだけでは当然データのやり取りを行うことは出来ません。データのやりとりを行わせたいアクティビティで、ContentResolver
づてにContentProvider
のメソッドを呼び出す必要があります。とはいってもそこまで複雑ではなく、単純なやり取りであれば非常に簡単なコードで済みます。以下は挿入・削除・更新の簡単な例です。
private fun testInsert() {
val values = ContentValues().apply {
put(Column_NAME, "INSERT")
}
val uri = contentResolver.insert(TEST_URI, values)
}
private fun testUpdate() {
val values = ContentValues().apply {
put(Column_NAME, "UPDATE")
}
val selection = "Colimn_NAME" + " = ?"
val selectionArgs = arrayOf("INSERT")
val rowsAffected = contentResolver.update(TEST_URI, values, selection, selectionArgs)
}
private fun testDelete() {
val selection = "Column_NAME" + " = ?"
val selectionArgs = arrayOf("UPDATE")
val rowsAffected = contentResolver.delete(TEST_URI, selection, selectionArgs)
}
どのメソッドも、ContentResolver
を使ってクエリをDBに送っていることが何となくわかると思います。このように、ContentProvider
での実装はContentResolver
を経由して扱います。
具体的に各メソッドの説明をします。testInsert
メソッドはColumn_NAME
というカラムにINSERT
という文字列を持つ新たな行を挿入するためのメソッドです。testUpdate
はColumn_NAME
がINSERT
という行全てをUPDATE
という文字列に更新します。testDelete
はColumn_NAME
がUPDATE
という行を全て削除します。
selection
とselectionArgs
は↑のように使ってあげることで、SQLインジェクションを防ぐ事が出来ます。selection
の?
が順にselectionArgs
の配列に格納されます。WHERE =
に続くSQL文において、実際に指定する値についてはselectionArgs
に格納しているだけです。
これらのメソッドをアクティビティで使ってあげるだけで、簡単にプロバイダの操作が出来ます。ぜひ参考にしてみてください。