#android #kotlin #kotlin-extension
#Android #kotlin #kotlin-расширение
Вопрос:
В Android для выполнения некоторых задач мы требуем от пользователя предоставления соответствующих разрешений. Полный процесс проверки и запроса разрешения включает в себя 3 шага: проверка разрешения, запрос разрешения и проверка результата. Если в разрешении отказано, тогда не нужно запускать эту задачу. Итак, чтобы упростить это, я написал следующий интерфейс и функцию расширения в ActivityExtensions.kt
private val permissionTaskSource = HashMap<Int, TaskCompletionSource<Boolean>>()
interface PermissionHandler {
@RequiresApi(Build.VERSION_CODES.M)
fun Activity.permissionRequest(requestCode: Int, vararg permissions: String): Task<Boolean> {
requestPermissions(permissions, requestCode)
val tcs = TaskCompletionSource<Boolean>()
permissionTaskSource[requestCode] = tcs
return tcs.task
}
fun permissionResult(requestCode: Int, grantResults: IntArray) {
permissionTaskSource[requestCode]!!.setResult(grantResults.all { it == PERMISSION_GRANTED })
permissionTaskSource.remove(requestCode)
}
}
suspend fun <T> T.requiresPermission(vararg permissions: String): Unit? where T : Activity, T : PermissionHandler {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
return Unit // If version lower than M then no need of runtime permissions.
if (permissions.all { ContextCompat.checkSelfPermission(this, it) == PERMISSION_GRANTED })
return Unit // If already all permissions granted, then no need to ask again.
val granted = permissionRequest(System.currentTimeMillis().toInt(), *permissions).await()
if (granted)
return Unit // Permission granted now
return null // Permission denied now
}
Всякий раз, когда требуются некоторые разрешения для выполнения задачи в activity или fragment, я могу использовать эту строку:
private suspend fun someTask() {
requiresPermission(/* list of required permissions */) ?: run{ /*permission denied. handle properly*/ return }
// Inside fragment this has to be called with requiresActivity() receiver.
...
}
Все это работает нормально.. но в каждом действии / фрагменте я должен написать эти 4 строки кода.
override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<out String>, grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
permissionResult(requestCode, grantResults)
}
Есть ли какой-нибудь способ переместить эти коды также в ActivityExtensions.kt
файл, чтобы сделать его более аккуратным и избежать повторяющегося кода?
Комментарии:
1. Это не ответ, но теперь удобнее работать с разрешениями с помощью Android Results API (об этом хорошо написано здесь: wajahatkarim.com/2020/05/activity-results-api-onactivityresult ).
2. @SergeiMikhailovskii Нью-Йоркский ресурс.. Я пройду через это.. Спасибо 🙂
3. Я предпочитаю повторять этот код в каждом действии и избегать наследования… но с наследованием это нужно делать только в BaseActivity и расширяет этот класс в каждом действии.
4. @ManuelMato могу я узнать, почему вы предпочитаете повторять код вместо наследования? (кроме замены
Activity
наMyActivity
везде выглядит некрасиво.)5. Поскольку несколько действий (1,23?) Будут заключаться в проверке разрешения местоположения, поэтому BaseActivity опасен, потому что в будущем, возможно, функциональность будет расширяться с помощью другого поведения, поэтому я предпочитаю функцию расширения