ContentProvider简单使用(读取系统联系人并展示到简单的ListView控件上),读取以及创建属于自己的内容提供器

ContentProvider一般用法有两种:一种是使用现有的ContentProvider读取和操作相应程序中的数据:
 * 另一种是创建自己的ContentProvider,给程序的数据提供外部访问接口
 *
 * 如果想要访问ContentProvider中共享的数据,就要借助ContentResolver类
 * 可以通过Context中的getContentResolver()获取该类的实例
 * ContentResolver中提供了update() delete() query() insert()方法用于增删改查
 *
 * 不同于SQLiteDatabase,ContentProvider中的增删改查都是不接收表名参数的,而是使用了一个Uri参数代替,
 * 这个参数成为内容URI。内容URI给ContentProvider中的数据建立了唯一标识符,主要有两部分组成,authority和path。
 * authority是用于对不同应用程序做区分的,一般采用包名进行命名。比如某程序包名为com.example.app,
 * 那么该应用的authority可以命名为com.example.app.privider。
 * path用于对同一应用程序中不同的表做区分的,通常添加到authority后面,比如某个应用数据库中存在两张表table1 table2
 * 这时可以将path分别命名为/table1 /table2,然后将authority和path进行组合,内容URI就变成了
 * com.example.app.provider/table1不过目前还是很难认出这个字符串是内容URI,所以还要在头部加上协议声明:
 * content://com.example.app.provider/table1  得到URI字符串后还需要解析成Uri对象才可以作为参数传入,解析方法如下
 * val uri = Uri.parse("content://com.example.app.provider/table1")
 * 现在就可以使用Uri对象查询table1表中的数据了,代码示例如下
 * val crusor = contentResolver.query(uri,projection,selection,selectionArgs,sortOrder)
 * 查询返回的是一个Cursor对象,这个时候就可以将数据从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"))
 * 上述代码使用了selection和selectionArgs参数来对想要更新的数据进行约束,防止所有的行都受影响
 * 删除数据
 * contentResolver.delete(uri,"column2 = ?",arrayOf("1")

读取系统联系人并展示到简单的ListView控件上,不要忘了AndroidManifest.xml的权限声明

package com.example.contactstest

import android.annotation.SuppressLint
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.ContactsContract
import android.widget.Adapter
import android.widget.ArrayAdapter
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)

        val contactsView : ListView = findViewById(R.id.contactsView)

        adapter = ArrayAdapter(this,android.R.layout.simple_list_item_1,contactsList)
        contactsView.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){
                    readContacts()
                }else{
                    Toast.makeText(this,"You denied the permission",
                    Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

    @SuppressLint("Range")
    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()
        }
    }
}

创建内容提供器

package com.example.databasetest

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.databasetest.provider"
    private var dbHelper : MyDatabaseHelper? = null

    /by lazy代码块是一种懒加载技术,一开始不执行,只有首次调用uriMatcher变量才会执行,并且将代码块最后一行的值返回
    private val uriMacher 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 delete(uri: Uri, selection: String?, selectionArgs: Array<String>?) = dbHelper?.let {
        /删除数据
        val db = it.writableDatabase
        val deletedRows = when(uriMacher.match(uri)){
            bookDir -> db.delete("Book",selection,selectionArgs)
            bookItem -> {
                val bookId = uri.pathSegments[1]
                db.delete("Book","id = ?", arrayOf(bookId))
            }
            categoryItem -> {
                val categoryId = uri.pathSegments[1]
                db.delete("Category","id = ?", arrayOf(categoryId))
            }
            categoryDir -> db.delete("Category",selection,selectionArgs)
            else ->0
        }
        deletedRows
    }?:0

    override fun getType(uri: Uri) = when(uriMacher.match(uri)){
        bookItem -> "vnd.android.cursor.item/vnd.com.example.databasetest.provider.book"
        bookDir -> "vnd.android.cursor.dir/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
    }

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

    override fun onCreate() = context?.let {
        dbHelper =  MyDatabaseHelper(it,"BookStore.db",2)
        true
    }?:false

    /Uri对象的getpathSegments:会将内容URI权限之后的部分以“/”进行分割,并将分割结果放入字符串,那么0存的是路径,1存的是id
    override fun query(
        uri: Uri, projection: Array<String>?, selection: String?,
        selectionArgs: Array<String>?, sortOrder: String?) = dbHelper?.let {
            /查询数据
            val db = it.readableDatabase
        val cursor = when(uriMacher.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 update(
        uri: Uri, values: ContentValues?, selection: String?,
        selectionArgs: Array<String>?
    ) = dbHelper?.let {
        val db = it.writableDatabase
        val updateRows = when(uriMacher.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 -> null
        }
        updateRows
    }?:0
}

读取内容提供器中的内容

package com.example.providertest

import android.annotation.SuppressLint
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Button
import androidx.core.content.contentValuesOf

class MainActivity : AppCompatActivity() {
    private var bookId : String? = null

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

        val query : Button = findViewById(R.id.queryData)
        val update : Button = findViewById(R.id.updateData)
        val delete : Button = findViewById(R.id.deleteData)
        val insert : Button = findViewById(R.id.insertData)

        insert.setOnClickListener {
            /添加数据
            val uri = Uri.parse("content://com.example.databasetest.provider/book")
            val values = contentValuesOf("name" to "A Clash of Kings",
            "author" to "George Martin","pages" to 1000,"price" to 22.33)
            val newUri = contentResolver.insert(uri,values)
            bookId = newUri?.pathSegments?.get(1)
        }

        query.setOnClickListener {
            /查询数据
            val uri = Uri.parse("content://com.example.databasetest.provider/book")
            contentResolver.query(uri,null,null,null,null)?.apply {
                while (moveToNext()){
                    val name = getString(getColumnIndex("name"))
                    val author = getString(getColumnIndex("author"))
                    val pages = getString(getColumnIndex("pages"))
                    val price = getString(getColumnIndex("price"))
                    Log.d("MainActivity","book name is $name")
                    Log.d("MainActivity","book author is $author")
                    Log.d("MainActivity","book pages is $pages")
                    Log.d("MainActivity","book price is $price")
                }
                close()
            }
        }

        update.setOnClickListener {
            /更新数据
            bookId?.let {
                val uri = Uri.parse("content://com.example.databasetest.provider/book/$it")
                val values = contentValuesOf("name" to "A Storm of Swords",
                "pages" to 1226,"price" to 24.33)
                contentResolver.update(uri,values,null,null)
            }
        }

        delete.setOnClickListener {
            /删除数据
            bookId?.let {
                val uri = Uri.parse("content://com.example.databasetest.provider/book/$it")
                contentResolver.delete(uri,null,null)
            }
        }
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,我是一个语言模型AI,无法提供完整的源码。但是,我可以给您提供一些参考资料和思路。 关于第一个问题,您需要了解以下几个知识点: 1. ContentProvider:Android中的一种数据存储机制,用于在应用程序之间共享数据。 2. SQLite数据库:Android中的一种轻量级的关系型数据库,用于存储结构化数据。 3. CRUD操作:即增加(Create)、读取(Retrieve)、更新(Update)、删除(Delete)的操作,是对数据库的基本操作。 基于以上知识点,您可以按照以下步骤实现: 1. 创建一个ContentProvider类,继承自android.content.ContentProvider,并实现相关方法,包括query、insert、update和delete等。 2. 在ContentProvider创建一个SQLiteOpenHelper类,用于管理数据库的创建和升级。 3. 在SQLiteOpenHelper中创建一个user表,包含id、name和age等字段。 4. 在ContentProvider的query、insert、update和delete方法中,分别实现对user表的CRUD操作。 5. 在测试程序中,通过ContentResolver调用ContentProvider中的接口,实现对user表的增删改查等操作。 关于第二个问题,您需要了解以下知识点: 1. ContentResolver:Android中的一种数据访问机制,用于访问ContentProvider中的数据。 2. Uri:一种用于标识ContentProvider中数据的统一资源标识符。 3. Cursor:一种用于遍历查询结果集的接口。 基于以上知识点,您可以按照以下步骤实现: 1. 在布局文件中添加一个ListView控件。 2. 在Activity中获取ListView对象,并创建一个SimpleCursorAdapter对象。 3. 使用ContentResolver查询短信数据,并将查询结果赋值给Cursor对象。 4. 将Cursor对象与SimpleCursorAdapter对象关联,将查询结果显示ListView中。 以上是大致的实现思路,具体的实现细节还需要您自行查找相关的资料和代码示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值