How to check permission is granted in ViewModel?

旧巷老猫 提交于 2020-06-11 02:37:06

问题


I need to ask permission for contacts and when application starts I'm asking,in ViewModel part I need to call method which requires permission. I need to check permission is granted by user or not and then call, but for checking permission I need to have access Activity. while in my ViewModel I don't have a reference to Activity and don't want to have, How I can overcome, the problem?


回答1:


I just ran into this problem, and I decided to use make use of LiveData instead.

Core concept:

  • ViewModel has a LiveData on what permission request needs to be made

  • ViewModel has a method (essentially callback) that returns if permission is granted or not

SomeViewModel.kt:

class SomeViewModel : ViewModel() {
    val permissionRequest = MutableLiveData<String>()

    fun onPermissionResult(permission: String, granted: Boolean) {
        TODO("whatever you need to do")
    }
}

FragmentOrActivity.kt

class FragmentOrActivity : FragmentOrActivity() {
    private viewModel: SomeViewModel by lazy {
        ViewModelProviders.of(this).get(SomeViewModel::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        ......
        viewModel.permissionRequest.observe(this, Observer { permission -> 
            TODO("ask for permission, and then call viewModel.onPermissionResult aftwewards")
        })
        ......
    }
}



回答2:


I have reworked the solution. The PermissionRequester object is everything you need to request permissions from any point where you have at least an application context. It uses its helper PermissionRequestActivity to accomplish this job.

@Parcelize
class PermissionResult(val permission: String, val state: State) : Parcelable
enum class State { GRANTED, DENIED_TEMPORARILY, DENIED_PERMANENTLY }
typealias Cancellable = () -> Unit
private const val PERMISSIONS_ARGUMENT_KEY = "PERMISSIONS_ARGUMENT_KEY"
private const val REQUEST_CODE_ARGUMENT_KEY = "REQUEST_CODE_ARGUMENT_KEY"

object PermissionRequester {
    private val callbackMap = ConcurrentHashMap<Int, (List<PermissionResult>) -> Unit>(1)
    private var requestCode = 256
    get() {
        requestCode = field--
        return if (field < 0) 255 else field
    }

    fun requestPermissions(context: Context, vararg permissions: String, callback: (List<PermissionResult>) -> Unit): Cancellable {
        val intent = Intent(context, PermissionRequestActivity::class.java)
                .putExtra(PERMISSIONS_ARGUMENT_KEY, permissions)
                .putExtra(REQUEST_CODE_ARGUMENT_KEY, requestCode)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        context.startActivity(intent)
        callbackMap[requestCode] = callback
        return { callbackMap.remove(requestCode) }
    }

    internal fun onPermissionResult(responses: List<PermissionResult>, requestCode: Int) {
        callbackMap[requestCode]?.invoke(responses)
        callbackMap.remove(requestCode)
    }
}

class PermissionRequestActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (savedInstanceState == null) {
            requestPermissions()
        }
    }

    private fun requestPermissions() {
        val permissions = intent?.getStringArrayExtra(PERMISSIONS_ARGUMENT_KEY) ?: arrayOf()
        val requestCode = intent?.getIntExtra(REQUEST_CODE_ARGUMENT_KEY, -1) ?: -1
        when {
            permissions.isNotEmpty() && requestCode != -1 -> ActivityCompat.requestPermissions(this, permissions, requestCode)
            else -> finishWithResult()
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        val permissionResults = grantResults.zip(permissions).map { (grantResult, permission) ->
            val state =  when {
                grantResult == PackageManager.PERMISSION_GRANTED -> State.GRANTED
                ActivityCompat.shouldShowRequestPermissionRationale(this, permission) -> State.DENIED_TEMPORARILY
                else -> State.DENIED_PERMANENTLY
            }
            PermissionResult(permission, state)
        }

        finishWithResult(permissionResults)
    }

    private fun finishWithResult(permissionResult: List<PermissionResult> = listOf()) {
        val requestCode = intent?.getIntExtra(REQUEST_CODE_ARGUMENT_KEY, -1) ?: -1
        PermissionRequester.onPermissionResult(permissionResult, requestCode)
        finish()
    }
}

Usage:

class MyViewModel(application: Application) : AndroidViewModel(application) {

    private val cancelRequest: Cancellable = requestPermission()

    private fun requestPermission(): Cancellable {
        return PermissionRequester.requestPermissions(getApplication(), "android.permission.SEND_SMS") {
            if (it.firstOrNull()?.state == State.GRANTED) {
                Toast.makeText(getApplication(), "GRANTED", Toast.LENGTH_LONG).show()
            } else {
                Toast.makeText(getApplication(), "DENIED", Toast.LENGTH_LONG).show()
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        cancelRequest()
    }
}



回答3:


I did something like this:

create an abstract class that extents AndroidViewModel which gives you access to the application context:

abstract class BaseViewModel(application: Application) : AndroidViewModel(application), CoroutineScope {

    private val job = Job()

    override val coroutineContext: CoroutineContext
        get() = job + Dispatchers.Main

    override fun onCleared() {
        super.onCleared()
        job.cancel()
    }
}

Now, create your view model by extending the BaseViewModel class and you will have access to the application context

class AdminViewModel(application: Application) : BaseViewModel(application) {
    .....
}

Now you always have access to a Context that you can use to get access to resources.



来源:https://stackoverflow.com/questions/44550851/how-to-check-permission-is-granted-in-viewmodel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!