第8章:跨程共享数据,探究ContentProvider(笔记)


8.1 ContentProvider简介
	
8.2 运行时权限

8.2.1 Android权限机制详解

	普通权限:
	
	危险权限:11组,30个权限,如果授权一组当中的一个,那么这组都视为授权。
	
	特殊权限:
	
	查看权限列表:https://blog.csdn.net/weixin_53545232/article/details/125498676?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166618925516782417022085%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=166618925516782417022085&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~times_rank-2-125498676-null-null.142^v59^pc_search_tree,201^v3^control_2&utm_term=android%20%E5%8D%B1%E9%99%A9%E6%9D%83%E9%99%90%E5%88%97%E8%A1%A8&spm=1018.2226.3001.4187


8.2.2 在程序运行时申请权限

	第一步:声明权限,
	
	
	第二步:判断这个(直接打电话权限)是否授权,是就调用call(),不是就调用ActivityCompat.requestPermissions
			申请这个(直接打电话权限)权限,再重写申请权限的逻辑,判断是否授权,是就调用call(),不是就提示,申请失败。
	    makeCall.setOnClickListener {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CALL_PHONE), 1)
            } else {
                call()
            }
        }
		
	# 重写请求权限的逻辑
	override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, 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 the permission", 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()
        }
    }
	
8.3 访问其他程序中的数据

8.3.1 ContentResolver的基本用法

	# 查询数据
	val uri = Uri.parse("content://com/example.app.provider/table1")
	val cursor = contentResolver.query(
		uri,	# 查询某一个程序下的某一张表
		projection,	# 查询的列表
		selection,	# where的约束条件
		selectionArgs,	# where占位符的值
		sortOrder)		# 查询结果的排序方式
		
	# 读取查询结果
	while(cursor.moveToNext()){
		val colum1 = cursor.getString(cursor.getColunmIndex("colunm1"))
		val colum2 = cursor.getInt(cursor.getColumnIndex("column2")
	}
	cursor.close()
	
	#  插入数据
	val values = contentValuesOf("colum1" to "text", "colum2" to 1)
	contentResolver.insert(uri, values)
	
	# 更新数据
	val values = contentValuesOf("colum1" to "")
	contentResolver.update(uri, values, "colum1 = ? and colum2 = ?", arrayOf("text", "1"))
	
	# 删除数据
	contentResolver.delete(uri, "colum1 = ?", arrayOf("text))
	
	
	
8.3.2 读取系统联系人

	第一步:声明权限。
    
	
	第二步:申请危险权限。

	    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, 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()
                }
            }
        }
    }
	
	第三步:读取系统联系人,显示到ListView。
	
	private val contactsList = ArrayList()
    private lateinit var adapter: ArrayAdapter
	adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, contactsList)
    contactsView.adapter = adapter
	
	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()
        }
    }
	

8.4 创建自己的ContentProvider

8.4.1 创建ContentProvider的步骤

	# 规则,
	# uri: content://com.example.provider/table1
	# uri: content://com.example.provider/table1/1     表示table1中id为1的数据
	
	# *匹配任意长度了字符
	# #匹配任意长度的数据
	# uri: content://com.example.provider/*				匹配任意表
	# uri: content://com.example.provider/table1/#     	匹配表中的任意行的数据
	
	
	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 onCreate(): Boolean {
			return false
		}

		override fun query(uri: Uri, projection: Array?, selection: String?, selectionArgs: Array?, sortOrder: String?): Cursor? {
			when (uriMatcher.match(uri)) {
				table1Dir -> {
					// 查询table1表中的所有数据
				}
				table1Item -> {
					// 查询table1表中的单条数据
				}
				table2Dir -> {
					// 查询table2表中的所有数据
				}
				table2Item -> {
					// 查询table2表中的单条数据
				}
			}
			return null
		}

		override fun insert(uri: Uri, values: ContentValues?): Uri? {
			return null
		}

		override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array?): Int {
			return 0
		}

		override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int {
			return 0
		}

		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
		}

	}
	
8.4.2 实现跨程序数据共享


	在共享端应用,实现如下这个类:(注意数据库版本号)
	
package com.example.databasetest

import android.content.ContentProvider
import android.content.ContentValues
import android.database.Cursor
import android.net.Uri
import android.content.UriMatcher
import android.os.CancellationSignal
import android.database.sqlite.SQLiteDatabase

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 later {
        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", 3)
        true
    } ?: false

    override fun query(
        uri: Uri,
        projection: Array?,
        selection: String?,
        selectionArgs: Array?,
        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?) =
        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?) = dbHelper?.let {
        // 删除数据
        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

	// 返回提供的表的Uri对应的MIME类型
    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
    }
}

	# 在获取数据端应用实现以下代码:
	
class MainActivity : AppCompatActivity() {

    var bookId: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        addData.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 1040, "price" to 22.85)
            val newUri = contentResolver.insert(uri, values)
            bookId = newUri?.pathSegments?.get(1)
            Log.d("MainActivity", "$bookId, $newUri")
            // MainActivity: 5, content://com.example.databasetest.provider/book/5
        }

        queryData.setOnClickListener {
            // 查询数据
            val uri = Uri.parse("content://com.example.databasetest.provider/book")
            contentResolver.query(uri, null, null, null, null)?.build {			//build使用了泛型实现的高阶函数,会报错,可改为apply
                while (moveToNext()) {
                    val name = getString(getColumnIndex("name"))
                    val author = getString(getColumnIndex("author"))
                    val pages = getInt(getColumnIndex("pages"))
                    val price = getDouble(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()
            }
        }

        updateData.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 1216, "price" to 24.05)
                contentResolver.update(uri, values, null, null)
            }
        }
        deleteData.setOnClickListener {
            // 删除数据
            bookId?.let {
                val uri = Uri.parse("content://com.example.databasetest.provider/book/$it")
                contentResolver.delete(uri, null, null)
            }
        }
    }
}


	



你可能感兴趣的:(Kotlin技术技巧,android,android,studio,ide)