15.1 ContentProvider的基本用法
访问ContentProvider中的共享的数据,就要借助ContentResolver类,可以通过Context中的getContentResolver()方法获取该类的实例。ContentResolver类中提供了一系列方法:
- insert()方法添加数据
- update()方法更新数据
- delete()方法删除数据
- query()方法查询数据
不同于SQLiteDatabase,ContentResolver中的增删改查不接收表明参数,而是使用一个Uri参数,这个参数被称为内容URI。
内容URI由两部分组成:authority和path。
- authority是用于区分不同的应用程序;一般采用包名的方式命名(
com.example.test.provider)。 - path用于区分不同的表;添加到authority后面(
com.example.test.provider/table1)
然后加上协议头
content://com.example.test.provider/table1
content://com.example.test.provider/table2
使用Uri.parse()方法解析成Uri对象。
val uri = Uri.parse("content://com.example.test.provider/table1")
查询数据
val cursor = contentResolver.query(
uri,
projection,
selection,
selectionArgs,
sortOrder
)
| query()方法参数 | 对应SQL部分 | 描述 |
|---|---|---|
| uri | from table_name | 指定查询某个应用程序的某一张表 |
| projection | selection column1, column2 | 指定查询的列名 |
| selection | where column = value | 指定where的约束条件 |
| selectionArgs | - | 为where种的占位符提供具体的值 |
| sortOrder | order by column1, column2 | 指定查询结果的排序方式 |
查询完成后返回的是Cursor对象
while (cursor.moveToNext()) {
val column1 = cursor.getString(cursor.getColumnIndex("column1"))
val column2 = cursor.getString(cursor.getColumnIndex("column2"))
}
cursor.close()
增加:
val values = contentValuesOf("column1" to "text", "column2" to 1)
contentResolver.insert(uri, values)
更新:
val values = contentValuesOf("column1" to "")
contentResolver.update(uri, values, "column1 = ? and column2 = ?", arrayOf("text", "1"))
删除:
contentResolver.delete(uri, "column2 = ?", arrayOf("1"))
15.2 读取联系人
使用一个ListView来显示读取的数据
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val contactsList = ArrayList<String>()
private lateinit var adapter: ArrayAdapter<String>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, contactsList)
binding.contactList.adapter = adapter
val readContactsPer = ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_CONTACTS)
if (readContactsPer != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.READ_CONTACTS), 2)
} else {
readContacts()
}
}
@SuppressLint("Range")
private fun readContacts() {
// 查询联系人数据
contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null)?.apply {
while (moveToNext()) {
// 获取联系人姓名
val name = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
val displayName = getString(getColumnIndex(name))
// 获取联系人手机号
val number = ContactsContract.CommonDataKinds.Phone.NUMBER
val displayNumber = getString(getColumnIndex(number))
contactsList.add("$displayName: $displayNumber")
}
adapter.notifyDataSetChanged()
close()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
1 -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
call()
} else {
Toast.makeText(this, "You denied Call the permission", Toast.LENGTH_SHORT).show()
}
}
2 -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
readContacts()
} else {
Toast.makeText(this, "You denied Contacts the permission", Toast.LENGTH_SHORT).show()
}
}
}
}
}
15.3 创建自己的ContentProvider
import android.content.ContentProvider
import android.content.ContentValues
import android.content.UriMatcher
import android.database.Cursor
import android.net.Uri
class DatabaseProvider : ContentProvider() {
private val bookDir = 0
private val bookItem = 1
private val categoryDir = 2
private val categoryItem = 3
private val authority = "com.example.filepersistencetest.provider"
private var dbHelper: MyDatabaseHelper? = null
private val uriMatcher by lazy {
val matcher = UriMatcher(UriMatcher.NO_MATCH)
matcher.addURI(authority, "book", bookDir)
matcher.addURI(authority, "book/#", bookItem)
matcher.addURI(authority, "category", categoryDir)
matcher.addURI(authority, "category/#", categoryItem)
matcher
}
override fun onCreate(): Boolean {
context?.let {
dbHelper = MyDatabaseHelper(it, "BookStore.db", 2)
return true
}
return false
}
override fun query(
uri: Uri, projection: Array<String>?, selection: String?,
selectionArgs: Array<String>?, sortOrder: String?
): Cursor? {
var cursor: Cursor? = null
dbHelper?.let {
val db = it.readableDatabase
cursor = when (uriMatcher.match(uri)) {
bookDir -> {
db.query("Book", projection, selection, selectionArgs, null, null, sortOrder)
}
bookItem -> {
val bookId = uri.pathSegments[1]
db.query("Book", projection, "id = ?", arrayOf(bookId), null, null, sortOrder)
}
categoryDir -> {
db.query("Category", projection, selection, selectionArgs, null, null, sortOrder)
}
categoryItem -> {
val categoryId = uri.pathSegments[1]
db.query("Category", projection, "id = ?", arrayOf(categoryId), null, null, sortOrder)
}
else -> null
}
}
return cursor
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
var uriReturn: Uri? = null
dbHelper?.let {
val db = it.writableDatabase
uriReturn = when (uriMatcher.match(uri)) {
bookDir, bookItem -> {
val newBookId = db.insert("Book", null, values)
Uri.parse("content://$authority/book/$newBookId")
}
categoryDir, categoryItem -> {
val newCategoryId = db.insert("Category", null, values)
Uri.parse("content://$authority/category/$newCategoryId")
}
else -> null
}
}
return uriReturn
}
override fun update(
uri: Uri, values: ContentValues?, selection: String?,
selectionArgs: Array<String>?
): Int {
var updateRows: Int = 0
dbHelper?.let {
val db = it.writableDatabase
updateRows = when (uriMatcher.match(uri)) {
bookDir -> {
db.update("Book", values, selection, selectionArgs)
}
bookItem -> {
val bookId = uri.pathSegments[1]
db.update("Book", values,"id = ?", arrayOf(bookId))
}
categoryDir -> {
db.update("Category", values, selection, selectionArgs)
}
categoryItem -> {
val categoryId = uri.pathSegments[1]
db.update("Category", values,"id = ?", arrayOf(categoryId))
}
else -> 0
}
}
return updateRows
}
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
var deleteRows: Int = 0
dbHelper?.let {
val db = it.writableDatabase
deleteRows = when (uriMatcher.match(uri)) {
bookDir -> {
db.delete("Book", selection, selectionArgs)
}
bookItem -> {
val bookId = uri.pathSegments[1]
db.delete("Book", "id = ?", arrayOf(bookId))
}
categoryDir -> {
db.delete("Category", selection, selectionArgs)
}
categoryItem -> {
val categoryId = uri.pathSegments[1]
db.delete("Category", "id = ?", arrayOf(categoryId))
}
else -> 0
}
}
return deleteRows
}
override fun getType(uri: Uri): String? {
var type: String? = null
type = when (uriMatcher.match(uri)) {
bookDir -> "vnd.android.cursor.dir/vnd.$authority.book"
bookItem -> "vnd.android.cursor.item/vnd.$authority.book"
categoryDir -> "vnd.android.cursor.dir/vnd.$authority.category"
categoryItem -> "vnd.android.cursor.item/vnd.$authority.category"
else -> null
}
return type
}
}
另一个应用程序操作
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val bookUriString = "content://com.example.filepersistencetest.provider/book"
var bookId: String? = null
@RequiresApi(Build.VERSION_CODES.R)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.addData.setOnClickListener {
addData()
}
binding.queryData.setOnClickListener {
queryData()
}
binding.updateData.setOnClickListener {
updateData()
}
binding.deleteData.setOnClickListener {
deleteData()
}
}
fun addData() {
val uri = Uri.parse(bookUriString)
val values = contentValuesOf(
"name" to "A Clash Of Kings",
"author" to "George Martin",
"pages" to 1040,
"price" to 22.85
)
val newUri = contentResolver.insert(uri, values)
bookId = newUri?.pathSegments?.get(1)
}
fun queryData() {
val uri = Uri.parse(bookUriString)
contentResolver.query(uri, null, null, null, null)?.apply {
while (moveToNext()) {
val name = getString(getColumnIndexOrThrow("name"))
val author = getString(getColumnIndexOrThrow("author"))
val pages = getInt(getColumnIndexOrThrow("pages"))
val price = getDouble(getColumnIndexOrThrow("price"))
Log.d("MainActivity", "info: $name, $author, $pages, $price")
}
close()
}
}
@RequiresApi(Build.VERSION_CODES.R)
fun updateData() {
bookId?.let {
val uri = Uri.parse("$bookUriString/$it")
val values = contentValuesOf(
"name" to "A Storm Of Swords",
"pages" to 1216,
"price" to 25.12
)
contentResolver.update(uri, null, null)
}
}
fun deleteData() {
bookId?.let {
val uri = Uri.parse("$bookUriString/$it")
contentResolver.delete(uri, null, null)
}
}
}