这里简单记录下,第一行代码第三版最后一章的实践。
实现 PermissionX 开源库
对运行时权限的 API 封装并不是一件容易的事,因为这个操作是有特定的上下文依赖的。一般需要在 Activity 中接收 onRequestPermissionsResult() 方法的回调才行,所以不能那个简单地将整个操作封装到一个独立的类中。
受此限制,也衍生出了一些特别的解决方案,比如将运行时权限的操作封装到 BaseActivity 中,或者提供一个透明的 Activity 来处理运行时权限等。
Google 在 Fragment 中提供了相同的 API,使得在 Fragment 也能申请运行时权限。Fragment 并不必须有界面,所以可以向 Activity 中添加一个隐藏的 Fragment,在这个隐藏的 Fragment 中对运行时权限 API 封装。
typealias PermissionCallback = (Boolean, List<String>) -> Unit
class InvisibleFragment : Fragment() {
private var callback: PermissionCallback? = null
fun requestNow(cb: PermissionCallback, vararg permissions: String) {
callback = cb
requestPermissions(permissions, 1)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
if (requestCode == 1) {
val deniedList = ArrayList<String>()
for ((index, result) in grantResults.withIndex()) {
if (result != PackageManager.PERMISSION_GRANTED) {
deniedList.add(permissions[index])
}
}
val allGranted = deniedList.isEmpty()
callback?.let { it(allGranted, deniedList) }
}
}
}
typealias 关键字可以用于给任意类型指定一个别名,从而让代码更加简洁易懂。
InvisibleFragment 中并没有重写 onCreateView() 方法来加载某个布局,因为它自然就是一个不可见的 Fragment,只需要将它添加到 Activity 中即可。
object PermissionX {
private const val TAG = "InvisibleFragment"
fun request(
activity: FragmentActivity,
vararg permissions: String,
callback: PermissionCallback
) {
val fragmentManager = activity.supportFragmentManager
val existedFragment = fragmentManager.findFragmentByTag(TAG)
val fragment = if (existedFragment != null) {
existedFragment as InvisibleFragment
} else {
val invisibleFragment = InvisibleFragment()
fragmentManager.beginTransaction().add(invisibleFragment, TAG).commitNow()
invisibleFragment
}
fragment.requestNow(callback, *permissions)
}
}
FragmentActivity 是 AppCompatActivity 的父类。
需要注意 permissions 参数在这里实际上是一个数组,对于数组,是不可以直接将它传递给另一个接收可变长参数的方法。* 表示将一个数组转换成可变长参数传递过去,而不是指针的意思。
总结
整体来说,加深了自己对 Kotlin 的理解与运用。电子书分享 👇
第一行代码第三版