1. はじめに
ContentProvider は、主に異なるアプリケーション間でのデータ共有機能を実現するために使用され、あるプログラムが別のプログラムのデータにアクセスできるようにし、アクセスされるデータのセキュリティを確保するための一連の仕組みを提供します。現在、ContentProvider を使用するのが、Android がプログラム間でデータを共有する標準的な方法です。ContentProvider は、プログラム内の個人データが漏洩する危険がないように、データのどの部分のみを共有するかを選択できます。
1.ContentResolverの基本的な使い方
各アプリケーションで、ContentProvider で共有されているデータにアクセスする場合は、ContentResolver クラスを使用する必要があります。このクラスのインスタンスは、 Context の getContentResolver() メソッドを通じて取得できます。ContentResolver は、データを追加、削除、変更、クエリするための一連のメソッドを提供します。insert() メソッドはデータの追加に使用され、update() メソッドはデータの更新に使用され、delete() メソッドはデータの削除に使用されます。 query() メソッド データのクエリに使用されます。既視感はありますか?そうです。これらのメソッドは SQLiteDatabase でも追加、削除、変更、クエリ操作を実行するために使用されますが、メソッド パラメーターが若干異なります。SQLiteDatabase とは異なり、ContentResolver の追加、削除、変更、クエリ メソッドはテーブル名パラメーターを受け入れませんが、代わりにコンテンツ URI と呼ばれる Uri パラメーターを使用します。コンテンツ URI は、ContentProvider 内のデータの一意の識別子を確立し、主に権限とパスの 2 つの部分で構成されます。権限は異なるアプリケーションを区別するために使用され、一般に競合を避けるためにアプリケーションのパッケージ名が命名に使用されます。たとえば、アプリケーションのパッケージ名が com.example.app の場合、アプリケーションに対応する権限は com.example.app.provider と名付けられます。パスは、同じアプリケーション内の異なるテーブルを区別するために使用され、通常は権限の後に追加されます。たとえば、アプリケーションのデータベースに table1 と table2 という 2 つのテーブルがあるとします。このとき、パスにそれぞれ /table1 と /table2 という名前を付け、権限とパスを組み合わせると、コンテンツ URI は com.example になります。 app.provider/table1 および com.example.app.provider/table2。ただし、これら 2 つの文字列を 2 つのコンテンツ URI として識別することは依然として困難であり、文字列の先頭にプロトコル ステートメントを追加する必要もあります。したがって、コンテンツ URI の最も標準的な形式は次のとおりです。
content://com.example.app.provider/table1
content://com.example.app.provider/table2
コンテンツ URI 文字列を取得した後、パラメーターとして渡す前に、それを Uri オブジェクトに解析する必要があります。解析方法も非常に簡単で、コードは次のとおりです。
val uri = Uri.parse("content://com.example.app.provider/table1")
2.使用する
val cursor = contentResolver.query(
uri,
projection,
selection,
selectionArgs,
sortOrder)
クエリが完了した後も Cursor オブジェクトが返されるので、Cursor オブジェクトからデータを 1 つずつ読み取ることができます。読み取りの考え方は、やはりカーソルの位置を移動してカーソルのすべての行を走査し、各行の対応する列のデータをフェッチすることです。コードは次のとおりです。
while (cursor.moveToNext()) {
val column1 = cursor.getString(cursor.getColumnIndex("column1"))
val column2 = cursor.getInt(cursor.getColumnIndex("column2"))
}
cursor.close()
最も難しいクエリ操作をマスターすると、残りの追加、変更、削除の操作はさらに簡単になります。まず、table1 にデータを追加する方法を見てみましょう。コードは次のとおりです。
val values = contentValuesOf("column1" to "text", "column2" to 1) contentResolver.insert(uri, values)
追加されるデータが引き続き ContentValues に組み立てられ、ContentResolver の insert() メソッドが呼び出され、Uri と ContentValues がパラメーターとして渡されることがわかります。
この新しく追加されたデータを更新して、column1 の値をクリアしたい場合は、ContentResolver の update() メソッドを使用できます。コードは次のとおりです。
val values = contentValuesOf("column1" to "")
contentResolver.update(uri, values, "column1 = ? and column2 = ?", arrayOf("text", "1"))
上記のコードでは、selection パラメーターとselectionArgs パラメーターを使用して更新されるデータを制約し、すべての行が影響を受けないようにすることに注意してください。最後に、ContentResolver の delete() メソッドを呼び出して、このデータ部分を削除できます。コードは次のとおりです。
contentResolver.delete(uri, "column2 = ?", arrayOf("1"))
使用
//<uses-permission android:name="android.permission.READ_CONTACTS" />
class MainActivity : AppCompatActivity() {
private val contactsList = ArrayList<String>()
private lateinit var adapter: ArrayAdapter<String>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, contactsList)
contactsView.adapter = adapter
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.READ_CONTACTS), 1)
} else {
readContacts()
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>,
grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
1 -> {
if (grantResults.isNotEmpty()
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
readContacts()
} else {
Toast.makeText(this, "You denied the permission",
Toast.LENGTH_SHORT).show()
}
}
}
}
private fun readContacts() {
// 查询联系人数据
contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, null, null, null)?.apply {
while (moveToNext()) {
// 获取联系人姓名
val displayName = getString(getColumnIndex(
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))
// 获取联系人手机号
val number = getString(getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER))
contactsList.add("$displayName\n$number")
}
adapter.notifyDataSetChanged()
close()
}
}
}
2 番目に、ContentProvider の使用
class MyProvider : ContentProvider() {
override fun onCreate(): Boolean {
return false
}
override fun query(uri: Uri, projection: Array<String>?, selection: String?,
selectionArgs: Array<String>?, sortOrder: String?): Cursor? {
return null
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
return null
}
override fun update(uri: Uri, values: ContentValues?, selection: String?,
selectionArgs: Array<String>?): Int {
return 0
}
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
return 0
}
override fun getType(uri: Uri): String? {
return null
}
}
(1) onCreate()。ContentProvider が初期化されるときに呼び出されます。通常、データベースの作成やアップグレードなどの操作はここで完了します。true が返された場合は ContentProvider の初期化が成功したことを示し、false が返された場合は失敗したことを示します。
(2) クエリ()。ContentProvider からデータをクエリします。uri パラメータはクエリするテーブルを決定するために使用され、projection パラメータはクエリする列を決定するために使用され、selection パラメータとselectionArgs パラメータはクエリする行を制限するために使用され、sortOrder パラメータは結果を並べ替えるために使用されます。クエリ結果は Cursor オブジェクトに格納され、返されます。
(3) 挿入()。データを ContentProvider に追加します。uri パラメータは追加するテーブルを決定するために使用され、追加するデータはvaluesパラメータに格納されます。追加が完了すると、新しいレコードを表す URI が返されます。
(4) update()。ContentProvider 内の既存のデータを更新します。uri パラメータは、どのテーブルのデータを更新するかを決定するために使用されます。新しいデータは、values パラメータに保存されます。selection パラメータとselectionArgs パラメータは、更新する行を制約するために使用され、影響を受ける行の数が返されます。戻り値として。
(5) 削除()。ContentProvider からデータを削除します。uri パラメータは削除するテーブルのデータを決定するために使用され、selection パラメータとselectionArgs パラメータは削除する行を制限するために使用され、削除された行の数が戻り値として返されます。
(6) getType()。受信したコンテンツ URI に基づいて、対応する MIME タイプを返します。多くのメソッドにはパラメーター uri があり、このパラメーターは contentresolver の追加、削除、変更、およびクエリ メソッドを呼び出すときにも渡されます。次に、受信した URI パラメーターを解析し、呼び出し元がアクセスすると予想されるテーブルとデータを分析する必要があります。