• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

安卓笔记四ContentProvider 和 运行时权限

武飞扬头像
Frms
帮助1


在Android 13(T)官方的获取权限不见得比其他辅助的库更复杂,具体用法 这里没有更新,请自行查阅资料

运行时权限

 安卓权限组分普通权限危险权限,每组又有多个,只要授权某组的一个,该组就默认全都授权,但组规则会变,不要基于此实现任何功能逻辑。

拨号为例

class MainActivity : AppCompatActivity()
{
	override fun onCreate(savedInstanceState: Bundle?)
	{
		super.onCreate(savedInstanceState)
		val button = Button(this)
		button.setOnClickListener {
			callPhone()
		}
		setContentView(button)
	}

	private fun callPhone()
	{
		try
		{
			// ACTION_CALL 直接拨打权限,需要在AndroidManifest申明
			// <uses-permission android:name="android.permission.CALL_PHONE"/>
			Intent(Intent.ACTION_CALL).run {
				data = Uri.parse("tel:10086")
				startActivity(this)
			}
		} catch (e: SecurityException)
		{
			e.printStackTrace()
		}
	}
}
学新通

在安卓6.0版本之前,这是没有问题的,更高版本,需要运行时处理,修复如下:


class MainActivity : AppCompatActivity()
{
	override fun onCreate(savedInstanceState: Bundle?)
	{
		super.onCreate(savedInstanceState)
		val button = Button(this)
		button.setOnClickListener {
			checkPermissions()
		}
		setContentView(button)
	}

	private fun callPhone()
	{
		try
		{
			// ACTION_CALL 直接拨打权限,需要在AndroidManifest申明
			// <uses-permission android:name="android.permission.CALL_PHONE"/>
			Intent(Intent.ACTION_CALL).run {
				data = Uri.parse("tel:10086")
				startActivity(this)
			}
		} catch (e: SecurityException)
		{
			e.printStackTrace()
		}
	}

	private fun checkPermissions()
	{
		// 第一步,判断用户是否已经给与授权
		if(ContextCompat.checkSelfPermission(this,
			Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED)
		{
			// 请求授权,不论结果如何,都会调用onRequestPermissionsResult()方法
			ActivityCompat.requestPermissions(
					this,
					arrayOf(Manifest.permission.CALL_PHONE),
					1 // 请求码,用于返回匹配结果, 应该 >= 0
			)
		} else {
			callPhone()
		}
	}

	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)
				{
					callPhone()
				} else {
					Toast.makeText(this, "你已拒绝", Toast.LENGTH_SHORT).show()
				}
			}
		}
	}
}
学新通

ContentProvider

确保安全性的同时,实现数据共享。用法有:

  1. 使用现有ContentProvider读取和操作应用程序数据
  2. 自定义ContentProvider ,给程序数据提供接口访问

使用现有ContentProvider

对于每个应用程序,访问ContentProvider需要借助ContentResolver,
在Kotlin中,直接引用contentResolver即可(语法糖)

ContentResolver提供的类似SQLiteDatabase的增删查改操作,不过较为容易。但都不再接收表名参数,而是使用Uri替代。标准格式如下:

content://authority.provider/path

authority:区分不同应用程序,一般为避免冲突,采用应用包名命名。
path:同一应用不同表名做区分

除此之外,还可以加上id

content://authority.provider/path/id

以id结尾可以有更大的拓展可能性,可以用通配符分别匹配这两种格式的内容URI,规则如下。

  1. * 表示 匹配任意长度的任意字符
  2. # 表示 匹配任意长度的梳子
    解析方法:
val uri = Uri.parse("content://authority.provider/path")

查询表

val cursor = contentResolver.query(
	uri,
	projection,
	selection,
	selectionArgs,
	sortOrder
)
参数 对应SQL码 描述
uri feom table_name 指定查询某应用下的一个表
projection select column1, column2 指定查询的列名
selection where column = value 指定where的约束条件
selectionArgs - 为where的占位符提供具体描述
sortOrder order by column1, column2 指定查询结果的排序方式

cursor表量Cursor对象,这样就能读取数据,依然是遍历所有行

while(cursor.moveToNext())
{
	val column1 = cursor.getString(cursor.getColumnIndex("column1"))
	val column2 = cursor.getInt   (cursor.getColumnIndex("column2"))
}

增加数据

contentResolver.insert(
	uri,
	contentValuesOf(
		"colum1"  to "text",
		"column2" to 1
	)
)

更新数据
若更新如下数据,把column1值清空,可由update()实现

contentResolver.update(
	uri,
	contentValuesOf("colum1"  to ""),
	"column1 = ? and column2 = ?",
	arrayOf("text", "1")
)

上述代码使用了selectionselectionArgs参数对想要更新的数据进行约束,防止所有行为都受到影响

删除
可以如下删除这条数据

contentResolver.delete(
	uri,
	"column1 = ?",
	arrayOf("1")
)

读取系统联系人

首先还是申请运行时权限、AndroidManiFest.xml写入信息,检查是否授权READ_CONTACTS等等,这里不再赘述。
关键读取代码如下:

@SuppressLint("Range")
private fun readContacts()
	{
		// 查询联系人数据
		contentResolver.query(
				// 这里封装好了Uri
				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
				))
			}
			// 关闭流
			close()
		}
	}
学新通

自定义ContentResolver

自定义主要是继承contentResolver然后重写方法,需要结合UriMatcher和数据库来实现,现有资料很多,这里便不再赘述。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgbkeac
系列文章
更多 icon
同类精品
更多 icon
继续加载