一、Android10为止所有危险权限
如需使用以下危险权限,需要在AndroidManifest.xml中进行声明。
二、申请电话权限并拨打电话示例
1.声明权限
<!-- 首先在AndroidManifest.xml中声明打电话权限 -->
<uses-permission android:name="android.permission.CALL_PHONE" />
2.在线程中向用户申请权限并拨打10086
override fun onCreate(...) {
...
// 先用checkSelfPermission()判断软件是否已经获得打电话权限
btn.setOnClickListener {
if(ContextCompat.checkSelfPermission(this,
Manifest.permission.CALL_PHONE) !=
PackageManager.PERMISSION_GRANTED) {
// 未获得权限,向用户申请
// 接受Activity,String权限和请求码3个参数
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.CALL_PHONE), 1)
} else {
// 已获得权限,拨打电话
call()
}
}
}
/* 用户拒绝/接受权限后的回调方法,在这里判断用户是否接受权限申请 */
override fun onRequestPermissionsResult(requestCode: Int,
permissions: Array<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()
}
}
三、访问其他程序中的数据——ContentResolver
ContentProvider有两种用法:1.用现有ContentProvider读取和操作程序中的数据。2.创建自己的ContentProvider,给外部程序访问数据的接口。先来学习如何访问其他程序中的数据。
1.ContentResolver基本用法
想访问ContentProvider中的内容就要用到ContentResolver,通过Context中的getContentResolver()方法获取实例。
ContentResolver可以进行增删改查操作,对应insert()、delete()、update()、query(),类似于SQLiteDatabase,不过第一参数不是表名,而是Uri参数。
Uri给ContentProvider中数据建立唯一标识符,由authority与path组成,authority一般以包名命名,path则是对同一程序中不同表做区分,因此标准URI格式如下:content://com.example.app.provider/table1。
val uri = Uri.parse("content://com.example.app.provider/table1")
2.读取系统联系人
添加权限声明
<!-- 添加权限声明 -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
完整代码
private val contactsList = ArrayList<String>() // 存放联系人
override fun onCreate(...) {
...
// 先判断是否已获得读取联系人权限
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_CONTACTS) !=
PackageManager.PERMISSION_GRANTED) {
// 未获得权限,向用户申请
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.READ_CONTACTS), 1)
} else {
// 已获得权限,读取联系人
readContacts()
}
}
override fun onRequestPermissionResult(requestCode: Int,
permissions: Array<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() {
// ContactsContact已经为我们做好了读取联系人Uri封装
contentResolver.query(ContactsContact.CommonDatakinds.
Phone.CONTENT_URI,null,null,null,null)?.apply{
while(moveToNext()) {
// 获取联系人姓名和手机号,用ContactsContact封装的常量
val name = getString(getColumnIndex(ContactsContact.
CommonDatakinds.Phone.DISPLAY_NAME))
val number = getString(getColumnInedx(COntactsContact.
CommonDatakinds.Phone.NUMBER))
contactsList.add("$name\n$number")
}
close()
}
}
四、创建自己的ContentProvider
要想实现跨程序共享数据的功能,需要新建一个类去继承ContentProvider来实现,ContentProvider类有6个抽象方法,需将这6个方法全部重写。
1.根据不同URI匹配不同内容
// 访问table1表中id为1的数据
"content://com.example.app.provider/table1/1"
// 访问table1表中所有数据
"content://com.example.app.provider/table1"
内容URI格式主要就上面两种
1.1.用通配符匹配上面两种格式
// *表示匹配任意长度任意字符
"content://com.example.app.provider/*" // 任意表内容
// #表示匹配任意长度数字
"content://com.example.app.provider/table1/#" // 表中任意数据
2.自定义ContentProvider完整代码
class DatabaseProvider : ContentProvider() {
// 分别表示读取整个book表还是book表中某一id数据
private val bookDir = 0
private val bookItem = 1
private val authority = "com.example.databasetest.provider"
private val dbHelper : MyDatabaseHelper? = null
// 懒加载,只有在uriMatcher被调用时才执行Lambda中代码
private val uriMatcher by lazy {
// UriMatcher用于解析Uri
val matcher = UriMatcher(UriMather.NO_MATCH)
// 添加需要响应的Uri格式
matcher.addURI(authority, "book", bookDir)
matcher.addURI(authority, "book/#", bookItem)
mather
}
override fun onCreate() = context?.let {
dbHelper = MyDatabaseHelper(it, "BookStore.db", 2)
true
} ?: false
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 -> {
// UriMatcher将path按/号分割,0是表名,1是id
val bookId = uri.pathSegments[1]
db.query("Book", projection, "id = ?",
arrayOf(bookId), 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")
}
else -> null
}
uriReturn
}
override fun update(uri: Uri, values: ContentValues?,
selection: String?, selectionArgs: Array<String>?) =
dbHelper?.let {
// 更新数据
val db = dbHelper.writableDatabase
val updateRows = when(uriMatcher.match(uri)) {
bookDir -> db.update("Book", values, selection,
selectionArgs)
bookItem -> {
val bookId = uri.pathSegments[1]
db.update("Book", values, "id = ?", arrayOf(bookId))
}
else -> 0
}
updateRows
} ?: 0
override fun delete(uri: Uri, selection: String?,
selectionArgs: Array<String>?) = dbHelper?.let {
//删除数据
val db = it.writableDatabase
val deletedRows = when(uriMatcher.match(uri)) {
bookDir -> db.delete("Book", selection, selectionArgs)
bookItem -> {
val categoryId = uri.pathSegments[1]
db.delete("Book", "id = ?", arrayOf(bookId))
}
else -> 0
}
deletedRows
} ?: 0
override fun getType(uri: Uri) = when(uriMatcher.match(uri)) {
// Uri以路径结尾返回dir,然后接上包名和表名
bookDir -> "vnd.android.cursor.dir/" +
"vnd.com.example.databasetest.provider.book"
// Uri以id结尾返回item,然后接上包名和表名
bookItem -> "vnd.android.cursor.item/" +
"vnd.com.example.databasetest.provider.book"
else -> null
}
}
UriMatcher用于匹配Uri内容,addURI()方法接收authority,path,自定义代码三个参数。调用match()方法时,传入Uri对象,返回值就是匹配上方addURI()方法添加的URI的自定义代码,因此我们可以判断调用者期望访问哪张表。
2.1.在AndroidManifest.xml中配置ContentProvider
自动创建的Provider不需要手动配置
<manifest ...>
<application ...>
<provider
android:name=".DatabaseProvider"
android:authorities="com.example.databasetest.provider"
android:enabled="true"
android:exported="true">
</provider>
</application>
</manifest>