当前位置:   article > 正文

Android ContentProvider基础知识学习笔记

Android ContentProvider基础知识学习笔记
1、动态申请权限
<uses-feature
        android:name="android.hardware.telephony"
        android:required="false" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
  • 1
  • 2
  • 3
  • 4
package com.jpc.contentprovidertest

import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat

/**
 * 运行时权限的核
 * 心就是在程序运行过程中由用户授权我们去执行某些危险操作,程序是不可以擅自做主去执行
 * 这些危险操作的。因此,第一步就是要先判断用户是不是已经给过我们授权了,借助的是
 * ContextCompat.checkSelfPermission()方法。checkSelfPermission()方法接收两
 * 个参数:第一个参数是Context,这个没什么好说的;第二个参数是具体的权限名,比如打电
 * 话的权限名就是Manifest.permission.CALL_PHONE。然后我们使用方法的返回值和
 * PackageManager.PERMISSION_GRANTED做比较,相等就说明用户已经授权,不等就表示用
 * 户没有授权。
 * 如果已经授权的话就简单了,直接执行拨打电话的逻辑操作就可以了,这里我们把拨打电话的
 * 逻辑封装到了call()方法当中。如果没有授权的话,则需要调用
 * ActivityCompat.requestPermissions()方法向用户申请授权。
 * requestPermissions()方法接收3个参数:第一个参数要求是Activity的实例;第二个参数
 * 是一个String数组,我们把要申请的权限名放在数组中即可;第三个参数是请求码,只要是唯
 * 一值就可以了,这里传入了1。
 *
 */
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val makeCall = findViewById<Button>(R.id.btn_make_call)
        makeCall.setOnClickListener {
            if (ContextCompat.checkSelfPermission(this,
                    android.Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this,
                    arrayOf(android.Manifest.permission.CALL_PHONE), 1)
            } else {
                call()
            }
        }

    }

    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, "你拒绝了该权限申请", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }
    private fun call(){
        try {
            val intent = Intent(Intent.ACTION_CALL)
            intent.data = Uri.parse("tel:10086")
            startActivity(intent)
        }catch (e: SecurityException){
            e.printStackTrace()
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
2、读取手机联系人
<uses-permission android:name="android.permission.READ_CONTACTS"/>
  • 1
package com.jpc.contentprovidertest

import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.ContactsContract
import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.ListView
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat

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)
        val listView = findViewById<ListView>(R.id.contacts_view)
        listView.adapter = adapter
        if(ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_CONTACTS)
            != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.READ_CONTACTS), 1)
        }else{
            readContacts()
        }
    }

    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, "你拒绝了该权限申请", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

    private fun readContacts() {
        // 查询联系人数据
        // ContactsContract.CommonDataKinds.Phone类已经帮我们做好了封装,提供了一个
        //CONTENT_URI常量,而这个常量就是使用Uri.parse()方法解析出来的结果
        contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null,null)
            ?.apply {
                while (moveToNext()){
                    // 获取联系人姓名
                    val name = getString(getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))
                    val phone = getString(getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER))
                    contactsList.add("$name\n$phone")
                }
                // 通知并刷新ListView
                adapter.notifyDataSetChanged()
                close() // 关闭Cursor对象
            }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
3、创建自己的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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

(1) onCreate()。初始化ContentProvider的时候调用。通常会在这里完成对数据库的创建和升级等操作,返回true表示ContentProvider初始化成功,返回false则表示失败。
(2) query()。从ContentProvider中查询数据。uri参数用于确定查询哪张表,projection参数用于确定查询哪些列,selection和selectionArgs参数用于约束查询哪些行,sortOrder参数用于对结果进行排序,查询的结果存放在Cursor对象中返回。
(3) insert()。向ContentProvider中添加一条数据。uri参数用于确定要添加到的表,待添加的数据保存在values参数中。添加完成后,返回一个用于表示这条新记录的URI。
(4) update()。更新ContentProvider中已有的数据。uri参数用于确定更新哪一张表中的数据,新数据保存在values参数中,selection和selectionArgs参数用于约束更新哪些行,受影响的行数将作为返回值返回。
(5) delete()。从ContentProvider中删除数据。uri参数用于确定删除哪一张表中的数据,selection和selectionArgs参数用于约束删除哪些行,被删除的行数将作为返回值返回。
(6) getType()。根据传入的内容URI返回相应的MIME类型。

一个标准的内容URI写法是:

content://com.example.app.provider/table1
  • 1

这就表示调用方期望访问的是com.example.app这个应用的table1表中的数据。
除此之外,我们还可以在这个内容URI的后面加上一个id,例如:

content://com.example.app.provider/table1/1
  • 1

这就表示调用方期望访问的是com.example.app这个应用的table1表中id为1的数据。
内容URI的格式主要就只有以上两种,以路径结尾表示期望访问该表中所有的数据,以id结尾表示期望访问该表中拥有相应id的数据。我们可以使用通配符分别匹配这两种格式的内容URI,规则如下。

  • *表示匹配任意长度的任意字符。
  • #表示匹配任意长度的数字。

所以,一个能够匹配任意表的内容URI格式就可以写成:

content://com.example.app.provider/*
  • 1

一个能够匹配table1表中任意一行数据的内容URI格式就可以写成:

content://com.example.app.provider/table1/#
  • 1

再借助UriMatcher这个类就可以轻松地实现匹配内容URI的功能。UriMatcher中提供了一个addURI()方法,这个方法接收3个参数,可以分别把authority、path和一个自定义代码传进去。这样,当调用UriMatcher的match()方法时,就可以将一个Uri对象传入。

class MyProvider : ContentProvider() {
 private val table1Dir = 0
 private val table1Item = 1
 private val table2Dir = 2
 private val table2Item = 3
 private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH)
 init {
 uriMatcher.addURI("com.example.app.provider", "table1", table1Dir)
 uriMatcher.addURI("com.example.app.provider ", "table1/#", table1Item)
 uriMatcher.addURI("com.example.app.provider ", "table2", table2Dir)
 uriMatcher.addURI("com.example.app.provider ", "table2/#", table2Item)
 }
 ...
 override fun query(uri: Uri, projection: Array<String>?, selection: String?,
 selectionArgs: Array<String>?, sortOrder: String?): Cursor? {
 when (uriMatcher.match(uri)) {
 table1Dir -> {
 // 查询table1表中的所有数据
 }
 table1Item -> {
 // 查询table1表中的单条数据
 }
 table2Dir -> {
 // 查询table2表中的所有数据
 }
 table2Item -> {
 // 查询table2表中的单条数据
 }
 }
 ...
 }
 ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
class MyProvider : ContentProvider() {
 ...
 override fun getType(uri: Uri) = when (uriMatcher.match(uri)) {
 table1Dir -> "vnd.android.cursor.dir/vnd.com.example.app.provider.table1"
 table1Item -> "vnd.android.cursor.item/vnd.com.example.app.provider.table1"
 table2Dir -> "vnd.android.cursor.dir/vnd.com.example.app.provider.table2"
 table2Item -> "vnd.android.cursor.item/vnd.com.example.app.provider.table2"
 else -> null
 }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
4、实战
class DatabaseProvider : ContentProvider() {
 private val bookDir = 0
 private val bookItem = 1
 private val categoryDir = 2
 private val categoryItem = 3
 private val authority = "com.example.databasetest.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() = context?.let {
 dbHelper = MyDatabaseHelper(it, "BookStore.db", 2)
 true
 } ?: false
www.blogss.cn
 override fun query(uri: Uri, projection: Array<String>?, selection: String?,
 selectionArgs: Array<String>?, sortOrder: String?) = dbHelper?.let {
 // 查询数据
 val db = it.readableDatabase
 val 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
 }
 cursor
 }
 override fun insert(uri: Uri, values: ContentValues?) = dbHelper?.let {
 // 添加数据
 val db = it.writableDatabase
 val 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
 }
 uriReturn
 }
 override fun update(uri: Uri, values: ContentValues?, selection: String?,
 selectionArgs: Array<String>?) = dbHelper?.let {
 // 更新数据
 val db = it.writableDatabase
 val updatedRows = 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
 }
 updatedRows
 } ?: 0
 override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?)
 = dbHelper?.let {
 // 删除数据
www.blogss.cn
 val db = it.writableDatabase
 val deletedRows = 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
 }
 deletedRows
 } ?: 0
 override fun getType(uri: Uri) = when (uriMatcher.match(uri)) {
 bookDir -> "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.book"
 bookItem -> "vnd.android.cursor.item/vnd.com.example.databasetest.provider.book"
 categoryDir -> "vnd.android.cursor.dir/vnd.com.example.databasetest.
 provider.category"
 categoryItem -> "vnd.android.cursor.item/vnd.com.example.databasetest.
 provider.category"
 else -> null
 }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/396437
推荐阅读
相关标签
  

闽ICP备14008679号