11

Jetpack来了,利用LiveData “换掉” RxPermission

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzAxMTI4MTkwNQ%3D%3D&%3Bmid=2650830440&%3Bidx=1&%3Bsn=7d8db2b8b0148bcf0181e2fe81ed0d68
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本文作者

作者: 反魂蝶五分

链接:

https://blog.csdn.net/u014290233/article/details/104383929

本文由作者授权发布。

1

概述

在以前,我们项目框架通常使用Rxjava+Retrofit+okhttp,所以使用RxPermissions进行动态权限申请就顺理成章了。随着Google新技术的推出,kotlin、jetpack成为大势所趋,如果项目中没有使用Rxjava,那么依赖于Rxjava的RxPermissions也就无法适用了。

RxPermissions 利用了Rxjava的观察者模式,而jetpack也提供了一种可观察的数据存储器类——LiveData,所以可以利用LiveData完成类似RxPermissions的动态权限申请框架,而且LiveData能够感知组件的生命周期,当 Activity 和 Fragment 的生命周期被销毁时,系统会立即退订它们,避免内存泄漏。

如果观察者(由 Observer 类表示)的生命周期处于 STARTED 或 RESUMED 状态,则 LiveData 会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者。为观察 LiveData 对象而注册的非活跃观察者不会收到更改通知。

2

代码实现

我们需要新建一个Fragment,用这个Fragment来进行权限的申请处理(新建Fragment的用途很广泛,比如Glide就是通过创建一个Fragment,然后通过这个Fragment感知生命周期),需要注意的是如果当前在Fragment里申请权限,需要用fragment.childFragmentManager,

class LivePermissions {
    ......

    constructor(activity: AppCompatActivity) {
        liveFragment = getInstance(activity.supportFragmentManager)
    }

    constructor(fragment: Fragment) {
        liveFragment = getInstance(fragment.childFragmentManager)
    }

    @Volatile
    private var liveFragment: LiveFragment? = null

    private fun getInstance(fragmentManager: FragmentManager) =
        liveFragment ?: synchronized(this) {
            liveFragment ?: if (fragmentManager.findFragmentByTag(TAG) == null) LiveFragment().run {
                fragmentManager.beginTransaction().add(this, TAG).commitNow()
                this
            } else fragmentManager.findFragmentByTag(TAG) as LiveFragment
        }
    ......
}

权限申请方法,在这里调用Fragment的申请申请方法并返回MutableLiveData,MutableLiveData是LiveData的子类,使用setValue或者postValue传入数据,通过LiveData.observe(LifecycleOwner,Observer)传入观察者观察数据更新,这样在Fragment里通过MutableLiveData将权限申请的结果回调回去。

    fun request(vararg permissions: String): MutableLiveData<PermissionResult> {
        return this.requestArray(permissions)
    }

    fun requestArray(permissions: Array<out String>): MutableLiveData<PermissionResult> {
        liveFragment!!.requestPermissions(permissions)
        return liveFragment!!.liveData
    }

    ......
}

创建LiveFragment继承Fragment。在requestPermissions方法里创建MutableLiveData并调用Android申请权限的方法,这里在onRequestPermissionsResult里处理返回结果。

返回结果这里创建了2个ArrayList,分别用来临时保持“拒绝”和“拒绝并不再询问”的权限,最终调用LiveData的setValue方法,利用LiveData观察者模式的特性,数据改变时会自动通知观察者。

internal class LiveFragment : Fragment() {

    lateinit var liveData :MutableLiveData<PermissionResult>

    private val PERMISSIONS_REQUEST_CODE = 100

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        retainInstance = true    //旋转屏幕时保存Fragment状态
    }

    @TargetApi(Build.VERSION_CODES.M)
    fun requestPermissions(permissions: Array<out String>) {
        liveData = MutableLiveData()
        requestPermissions(permissions, PERMISSIONS_REQUEST_CODE)
    }


    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        if (requestCode == PERMISSIONS_REQUEST_CODE) {
            val denyPermission = ArrayList<String>()
            val rationalePermission = ArrayList<String>()
            for ((index, value) in grantResults.withIndex()) {
                if (value == PackageManager.PERMISSION_DENIED) {
                    if (shouldShowRequestPermissionRationale(permissions[index])) {
                        rationalePermission.add(permissions[index])
                    } else {
                        denyPermission.add(permissions[index])
                    }
                }
            }
            if (denyPermission.isEmpty() && rationalePermission.isEmpty()) {
                liveData.value = PermissionResult.Grant
            } else {
                if (rationalePermission.isNotEmpty()) {
                    liveData.value = PermissionResult.Rationale(rationalePermission.toTypedArray())
                } else if (denyPermission.isNotEmpty()) {
                    liveData.value = PermissionResult.Deny(denyPermission.toTypedArray())
                }
            }

        }
    }

}

在最后返回权限的权限处理选项时,使用kotlin的sealed关键字,来确保在项目里使用when时能安全的判断每个权限每种可能的情况。

sealed class PermissionResult {
    object Grant : PermissionResult()    //全部同意
    class Deny(val permissions: Array<String>) : PermissionResult()    //拒绝且勾选了不再询问,permissions——被拒绝的权限
    class Rationale(val permissions: Array<String>) : PermissionResult()    //只是拒绝,没有勾选不再询问,permissions——被拒绝的权限
}

代码已托管到github,欢迎star, 地址:

https://github.com/LGD2009/LivePermissions

项目已发布到jcenter,可直接引用。

3

使用方法

1.添加依赖

implementation 'com.ftd.livepermissions:livepermissions:1.0.0'

2.添加代码

//申请权限
LivePermissions(this).request(
    Manifest.permission.WRITE_EXTERNAL_STORAGE,
    Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.CAMERA
).observe(this, Observer {
    when (it) {
        is PermissionResult.Grant -> {  //权限允许
            Toast.makeText(this, "Grant", Toast.LENGTH_SHORT).show()
        }
        is PermissionResult.Rationale -> {  //权限拒绝
            it.permissions.forEach {s->                      
                println("Rationale:${s}")//被拒绝的权限
            }
            Toast.makeText(this, "Rationale", Toast.LENGTH_SHORT)
                .show()
        }
        is PermissionResult.Deny -> {   //权限拒绝,且勾选了不再询问
            it.permissions.forEach {s->
                println("deny:${s}")//被拒绝的权限
            }
            Toast.makeText(this, "deny", Toast.LENGTH_SHORT).show()
        }
    }
})

相关资料

LiveData 概览

https://developer.android.google.cn/topic/libraries/architecture/livedata

What are sealed classes in Kotlin?

https://stackoverflow.com/questions/50772328/what-are-sealed-classes-in-kotlin?r=SearchResults

推荐阅读

与“阿里”的flutter-go三剑合璧

我感觉我学了一个假的Android...

WebView,RecyclerView 多布局连贯滑动

vEVjqa7.jpg!web

扫一扫  关注我的公众号

如果你想要跟大家分享你的文章,欢迎投稿~

┏(^0^)┛明天见!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK