前言
随着谷歌的Jetpack在国外普及使用,国内越来越多的开发者开始使用 Kotlin + Jetpack去构建自己的项目。而LiveData是谷歌在Jetpack中为开发者提供的基于观察者模式实现的数据存储器。LiveData不仅可以实现数据观察监听,同时通过LifeCycles内部感知Activity和Fragment的生命周期,在生命周期结束时自动回收,释放资源,防止内存泄漏。
Lifecycles包含有关Activity与Fragment生命周期状态的信息,并允许其他对象观察此状态,
用于观察组件(Activtiy、Fragment)的生命周期状态。
功能实现
通过添加Fragment方式来实现权限的申请,许多框架都是通过添加Fragment的方法实现的,例如:Glide就是通过添加Fragment的方式来感知生命周期的变化。
LiveDataFragment
LiveDataFragment是继承自Fragment,是权限申请的直接发起者,同时也是权限申请结果的回调的直接接收者,并将结果赋值到LiveData的Value上。代码如下:
class LiveDataFragment : Fragment() {
val liveData by lazy {
MutableLiveData<PermissionResult>()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
retainInstance = true
}
@TargetApi(Build.VERSION_CODES.M)
fun requestPermission(permissions: Array<out String>) {
requestPermissions(permissions, PERMISSIONS_REQUEST_CODE)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSIONS_REQUEST_CODE) {
val denyPermissions = mutableListOf<PermissionBean>()
grantResults.forEachIndexed { index, result ->
if (result == PackageManager.PERMISSION_DENIED) {
val permission = permissions[index]
val isRetryEnable = shouldShowRequestPermissionRationale(permission)
denyPermissions.add(PermissionBean(permission, isRetryEnable))
}
}
if (denyPermissions.isEmpty()) {
liveData.value = PermissionResult.Grant
} else {
liveData.value = PermissionResult.Deny(denyPermissions)
}
}
}
companion object {
const val PERMISSIONS_REQUEST_CODE = 100;
}
}
PermissionResult
PermissionResult是权限申请结果数据接收类,将PermissionBean存储到集合中。
sealed class PermissionResult {
object Grant : PermissionResult()
class Deny(val permissions: List<PermissionBean>) : PermissionResult()
}
PermissionBean
PermissionBean是单个权限申请状态的存储对象,被PermissionResult持有。
/**
* @param permissionName 权限名称
* @param isRetryEnable 被拒权限是否可以再次申请
*/
data class PermissionBean(var permissionName: String, var isRetryEnable: Boolean)
requestPermission
请求权限的方法,使用了Kotlin的语法糖,基于Activity和Fragment的扩展方法,同时也是顶部方法,在任何可以获取到Activity和Fragment的地方都可以执行。
const val TAG = "permission"
fun Fragment.requestPermission(vararg permissions: String) =
getInstance(childFragmentManager).apply { requestPermission(permissions) }.liveData
fun AppCompatActivity.requestPermission(vararg permissions: String) =
getInstance(supportFragmentManager).apply { requestPermission(permissions) }.liveData
private fun getInstance(manager: FragmentManager) = synchronized(manager) {
val findFragment = manager.findFragmentByTag(TAG)
if (findFragment == null) LiveDataFragment().apply {
manager.beginTransaction().add(this, TAG).commitNow()
}
else findFragment as LiveDataFragment
}
使用方法
使用时,将requestPermission方法复制到一个文件的顶部,即可在Activity或者Fragment中使用requestPermission来请求权限,如图:
代码如下:class MainActivity : AppCompatActivity() {
companion object {
const val TAG = "permissionnnnn"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tvTest.setOnClickListener {
requestPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CAMERA,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.ACCESS_FINE_LOCATION
).observe(this, Observer {
when (it) {
is PermissionResult.Grant -> {
Log.d(TAG, "申请权限成功")
}
is PermissionResult.Deny -> {
it.permissions.forEach { per ->
Log.d(
TAG, "拒绝的权限:${per.permissionName} 是否可以重复申请:${per.isRetryEnable}"
)
}
}
}
})
}
}
}
写在最后
身为一名搬砖的技术人员,只有通过持续学习,才能让自己的砖搬得越来越好。