Android 四大组件之ContentProvider

ContentProvider总结

概述

  • ContentProvider主要用于在不同的程序之间实现数据共享的功能,保证了数据的安全性
  • ContentProvider时Android实现跨程序共享数据的标准方式

基本用法

API说明

  • 访问ContentProvider中共享的数据,需要借助ContentResolver类,通过Context#getContentResolver()方法获取对象。
  • ContentResolver提供一系列方法用于对数据的操作:
    • insert() 添加数据
    • update() 更新数据
    • delete() 删除数据
    • query() 查询数据
  • ContentResolver中的增删改查需要使用URI,URI主要由两部分组成:
    • authority:用于区分不同的应用程序,如某应用的包名为com.example.app,则authority可以命名为com.example.app.provider
    • path:用于同一程序中不同的表做区分,如某应用存在来鼓掌表table1和table2,则path可以分别命名为/table1/table2
    • 在头部添加协议并将authority和path进行组合,URI变成content://com.example.app.provider/table1content://com.example.app.provider/table2

使用

val uri = Uri.parse("content://com.example.app.provider/table1")
contentResolver.query(uri,
                      projection,
                      selection,
                      selectionArgs,
                      sortOrder
                     )

ContentResolver中的query()方法与SQLiteDatabase中的query()方法比较像:

query()方法参数 对应SQL语句 说明
uri from table_name 查询某张表
projection select solumn1, column2 查询的字段
selection where column = value where约束条件
selectionArgs - where约束条件的值
sortOrder order by column1, column2 排序方式

读取系统联系人

class MainActivity : AppCompatActivity() {
    
    

    private lateinit var listView: ListView
    private lateinit var adapter: ArrayAdapter<String>
    private val contactsList = ArrayList<String>()

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        listView = findViewById<ListView>(R.id.listView)
        adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, contactsList)
        listView.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<out String>,
        grantResults: IntArray,
    ) {
    
    
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when (requestCode) {
    
    
            1 -> {
    
    
                if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    
    
                    readContacts()
                } else {
    
    
                    Toast.makeText(this, "授权失败", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

    //读取手机联系人
    private fun readContacts() {
    
    
        // content://com.android.contacts/data/phones
        val uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI 
        val cursor = contentResolver.query(uri, null, null, null, null)
        if (cursor != null) {
    
    
            while (cursor.moveToNext()) {
    
    
                val displayName =
                cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))
                val number =
                cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
                contactsList.add("$displayName - $number")
            }
            adapter.notifyDataSetChanged()
            cursor.close()
        }
    }
}

自定义ContentProvider

API说明

  • 自定义ContentProvider需要实现6个抽象方法:
    • onCreate() 初始化时调用。通常在这里完成数据库的创建和升级等操作,返回true表示初始化成功,返回false则表示失败
    • query() 从ContentProvider中查询数据
    • insert() 向ContentProvider中添加一条数据
    • update() 更新ContentProvider中的数据
    • delete() 删除ContentProvider中的数据
    • getType() 返回MIME类型
  • 在URI后面添加id,如content://com.example.app.provider/table/1表示table中id为1的数据,除了可以传数字还使用通配符:
    • * 表示匹配任意长度的任意字符,匹配任意表content://com.example.app.provider/*
    • # 表示匹配任意长度的数字,匹配任意idcontent://com.example.app.provider/table/#
  • 可以借助UriMatcher类实现匹配URI的功能,UriMatcher#addURI()方法负责添加URI,这个方法有3个参数:authority、path、code值;UriMatcher#match()方法负责匹配URI,匹配成功返回code值

自定义ContentProvider类

新建一个项目,并在该项目内操作以下步骤:

创建数据库类

private const val DB_NAME = "BookStore.db"
private const val VERSION = 2

class MyDatabaseHelper(context: Context) :
    SQLiteOpenHelper(context, DB_NAME, null, VERSION) {
    
    

    private val createBook = """
        create table $TAB_BOOK (
        id integer primary key autoincrement,
        author text,
        price real,
        pages integer,
        name text,
        category_id integer
        )
    """.trimIndent()

    private val createCategory = """
        create table $TAB_CATEGORY (
        id integer primary key autoincrement,
        category_name text,
        category_code integer
        )
    """.trimIndent()

    override fun onCreate(db: SQLiteDatabase) {
    
    
        db.execSQL(createBook)
        db.execSQL(createCategory)
    }

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
    
    
        if (oldVersion <= 1) {
    
    
            db.execSQL(createCategory)
        }
        if (oldVersion <= 2) {
    
    
            db.execSQL("alter table $TAB_BOOK add column category_id integer")
        }
    }
}

自定义ContentProvider类

class DatabaseProvider : ContentProvider() {
    
    
    private var dbHelper: MyDatabaseHelper? = null

    private val authority = "com.example.databaseprovider.provider"

    private val bookDir = 0 //访问所有数据
    private val bookItem = 1 //访问指定id的数据
    private val categoryDir = 2
    private val categoryItem = 3

    private val uriMatcher by lazy {
    
    
        val uriMatcher = UriMatcher(UriMatcher.NO_MATCH)
        uriMatcher.addURI(authority, "book", bookDir)
        uriMatcher.addURI(authority, "book/#", bookItem)
        uriMatcher.addURI(authority, "category", categoryDir)
        uriMatcher.addURI(authority, "category/#", categoryItem)
        uriMatcher
    }

    override fun onCreate(): Boolean {
    
    
        return context?.let {
    
    
            dbHelper = MyDatabaseHelper(it)
            true
        } ?: false
    }

    /**
     * 查询数据
     */
    override fun query(
        uri: Uri,
        projection: Array<out String>?,
        selection: String?,
        selectionArgs: Array<out String>?,
        sortOrder: String?,
    ): Cursor? {
    
    
        var cursor: Cursor? = null
        dbHelper?.let {
    
    
            val db = it.readableDatabase
            when (uriMatcher.match(uri)) {
    
    
                bookDir -> {
    
    
                    cursor = db.query(TAB_BOOK,
                        projection,
                        selection,
                        selectionArgs,
                        null,
                        null,
                        sortOrder)
                }
                bookItem -> {
    
    
                    val bookId = uri.pathSegments[1]
                    cursor =
                        db.query(TAB_BOOK,
                            projection,
                            "id=?",
                            arrayOf(bookId),
                            null,
                            null,
                            sortOrder)
                }
                categoryDir -> {
    
    
                    cursor = db.query(TAB_CATEGORY,
                        projection,
                        selection,
                        selectionArgs,
                        null,
                        null,
                        sortOrder)
                }
                categoryItem -> {
    
    
                    val categoryId = uri.pathSegments[1]
                    cursor = db.query(TAB_CATEGORY,
                        projection,
                        "id=?",
                        arrayOf(categoryId),
                        null,
                        null,
                        sortOrder)
                }
            }
        }
        return cursor
    }

    /**
     * 添加数据
     */
    override fun insert(uri: Uri, values: ContentValues?): Uri? {
    
    
        var uriReturn: Uri? = null
        dbHelper?.let {
    
    
            val db = it.writableDatabase
            when (uriMatcher.match(uri)) {
    
    
                bookDir, bookItem -> {
    
    
                    val newBookId = db.insert(TAB_BOOK, null, values)
                    uriReturn = Uri.parse("content://$authority/book/$newBookId")
                }
                categoryDir, categoryItem -> {
    
    
                    val newCategoryId = db.insert(TAB_CATEGORY, null, values)
                    uriReturn = Uri.parse("content://$authority/category/$newCategoryId")
                }
            }
        }
        return uriReturn
    }

    override fun update(
        uri: Uri,
        values: ContentValues?,
        selection: String?,
        selectionArgs: Array<out String>?,
    ): Int {
    
    
        var updateRows = 0
        dbHelper?.let {
    
    
            val db = it.writableDatabase
            when (uriMatcher.match(uri)) {
    
    
                bookDir -> {
    
    
                    updateRows = db.update(TAB_BOOK, values, selection, selectionArgs)
                }
                bookItem -> {
    
    
                    val bookId = uri.pathSegments[1]
                    updateRows = db.update(TAB_BOOK, values, "id=?", arrayOf(bookId))
                }
                categoryDir -> {
    
    
                    updateRows = db.update(TAB_CATEGORY, values, selection, selectionArgs)
                }
                categoryItem -> {
    
    
                    val categoryId = uri.pathSegments[1]
                    updateRows = db.update(TAB_CATEGORY, values, "id=?", arrayOf(categoryId))
                }
            }
        }
        return updateRows
    }

    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
    
    
        var deleteRows = 0
        dbHelper?.let {
    
    
            val db = it.writableDatabase
            when (uriMatcher.match(uri)) {
    
    
                bookDir -> {
    
    
                    deleteRows = db.delete(TAB_BOOK, selection, selectionArgs)
                }
                bookItem -> {
    
    
                    val bookId = uri.pathSegments[1]
                    deleteRows = db.delete(TAB_BOOK, "id=?", arrayOf(bookId))
                }
                categoryDir -> {
    
    
                    deleteRows = db.delete(TAB_CATEGORY, selection, selectionArgs)
                }
                categoryItem -> {
    
    
                    val categoryId = uri.pathSegments[1]
                    deleteRows = db.delete(TAB_CATEGORY, "id=?", arrayOf(categoryId))
                }
            }
        }
        return deleteRows
    }

    override fun getType(uri: Uri): String? {
    
    
        return when (uriMatcher.match(uri)) {
    
    
            bookDir -> {
    
    
                "vnd.android.cursor.dir/vnd.com.example.databaseprovider.provider/book"
            }
            bookItem -> {
    
    
                "vnd.android.cursor.item/vnd.com.example.databaseprovider.provider/book"
            }
            categoryDir -> {
    
    
                "vnd.android.cursor.dir/vnd.com.example.databaseprovider.provider/category"
            }
            categoryItem -> {
    
    
                "vnd.android.cursor.item/vnd.com.example.databaseprovider.provider/category"
            }
            else -> null
        }
    }
}

AndroidManifest.xml文件里注册Provider,并设置相关权限

<permission
            android:name="com.example.databaseprovider.permission.PERMISSION_READ"
            android:protectionLevel="normal" />
<permission
            android:name="com.example.databaseprovider.permission.PERMISSION_WRITE"
            android:protectionLevel="normal" />

<provider
          android:name=".DatabaseProvider"
          android:authorities="com.example.databaseprovider.provider"
          android:enabled="true"
          android:exported="true"
          android:readPermission="com.example.databaseprovider.permission.PERMISSION_READ"
          android:writePermission="com.example.databaseprovider.permission.PERMISSION_WRITE" />

使用ContentProvider

再新建一个项目,并在该项目中操作以下步骤:

AndroidManifest.xml文件里声明权限

<uses-permission android:name="com.example.databaseprovider.permission.PERMISSION_READ" />
<uses-permission android:name="com.example.databaseprovider.permission.PERMISSION_WRITE" />

//在Android11上需要声明
<queries>
    <package android:name="com.example.databaseprovider" />
</queries>
class MyProviderActivity : AppCompatActivity() {
    
    

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_my_provider)
    }

    fun addData(v: View) {
    
    
        val uri = Uri.parse("content://com.example.databaseprovider.provider/book")
        var contentValues = ContentValues().apply {
    
    
            put("name", "西游记1")
            put("author", "吴承恩")
            put("pages", "1008")
            put("price", "98")
        }
        var contentValues2 = ContentValues().apply {
    
    
            put("name", "哈利波特2")
            put("author", "罗琳")
            put("pages", "111")
            put("price", "66.77")
        }
        contentResolver.insert(uri, contentValues)
        contentResolver.insert(uri, contentValues2)
    }

    fun queryData(v: View) {
    
    
        val uri = Uri.parse("content://com.example.databaseprovider.provider/book")
        val cursor = contentResolver.query(uri, null, null, null, null)
        if (cursor != null) {
    
    
            while (cursor.moveToNext()) {
    
    
                val name = cursor.getString(cursor.getColumnIndex("name"))
                val author = cursor.getString(cursor.getColumnIndex("author"))
                val pages = cursor.getString(cursor.getColumnIndex("pages"))
                val price = cursor.getString(cursor.getColumnIndex("price"))
                Log.e("ContentProvider", "$name $author $pages $price")
            }
            cursor.close()
        }
    }

    fun updateData(v: View) {
    
    
        val bookId = 1
        val uri = Uri.parse("content://com.example.databaseprovider.provider/book/$bookId")
        val contentValues = ContentValues().apply {
    
    
            put("price", "678")
        }
        contentResolver.update(uri, contentValues, null, null)
    }

    fun deleteData(v: View) {
    
    
        val bookId = 1
        val uri = Uri.parse("content://com.example.databaseprovider.provider/book/$bookId")
        contentResolver.delete(uri, null, null)
    }
}

代码下载

猜你喜欢

转载自blog.csdn.net/qq_14876133/article/details/119107181