IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android 四大组件之ContentProvider -> 正文阅读

[移动开发]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语句说明
urifrom table_name查询某张表
projectionselect solumn1, column2查询的字段
selectionwhere column = valuewhere约束条件
selectionArgs-where约束条件的值
sortOrderorder 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)
    }
}

代码下载

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-07-27 16:20:36  更:2021-07-27 16:22:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/7 11:43:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码