基於Jetpack的LiveData動態權限申請

  在以前,我們項目框架通常使用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 對象而註冊的非活躍觀察者不會收到更改通知。

代碼實現

  我們需要新建一個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的申請申請方法並返回MutableLiveDataMutableLiveDataLiveData的子類,使用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,分別用來臨時保持“拒絕”和“拒絕並不再詢問”的權限,最終調用LiveDatasetValue方法,利用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,可直接引用。

使用方法

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()
                    }
                }
            })

相關資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章