最初的问题(18/05/2020):
所以有了最新的更新
- androidx.fragment:fragment:1.3.0- alpha07
至
- androidx.fragment:fragment:1.3.0- alpha08
我得到错误:
FragmentXY 在创建后尝试注册ForActivityResult。片段必须在创建之前调用 registerForActivityResult()(即初始化、onAttach() 或 onCreate())。
在向用户显示有关这些权限的使用以及为什么需要这些权限的信息之后,我曾经在我的 StartFragment(单活动应用程序,onViewCreated 中)中检查权限。在过去的 3(?)个月里,一切都运行良好。
我在更改日志中看到:
行为改变
[...]
在 onCreate() 之后调用 registerForActivityResult() 现在会抛出一个异常,表明这是不允许的,而不是在配置更改后静默地失败交付结果。(b/162255449) "
我暂时降级回 1.3.0-alpha07 版本。
但是,如果我在创建视图后需要在 Fragments 中使用registerForActivityResult (例如权限),那么在升级到 1.3.0-alpha08 版本时我该怎么做?
文档声明我应该在我的 Fragment 的 onCreate 中使用 launch() (见下文),但这意味着我必须在创建视图之前这样做,这与我的应用程序流程相矛盾。
行为改变
[...]
您现在可以在片段的 onCreate() 生命周期方法中对 ActivityResultLauncher 调用 launch()。(b/161464278) "
由于这种行为似乎是开发人员有意为之,它不是错误或其他任何东西,但我如何在 onCreate 之后继续使用 ActivityResults?有任何想法吗?
编辑(2020 年 5 月 19 日):
感谢@A.Andriyishyna,我明白注册(在 onCreate 中)和执行(在需要时,例如在 onViewCreated 中)必须单独处理。问题是我在其他文件中有方便的内联函数(感谢 Flywith24),这有助于我将权限 BL 与视图(片段)分开。
有没有办法保留这些内联函数而不必彻底改变它们?
- 分段
class GalleryFragment: ScopedFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initializePermissions(requiredContext)
}
private fun initializePermissions(context: Context) {
storagePermissions(
context = context,
actionOnGranted = { showImages() },
actionOnDeclined = { showNoAccess() },
actionRepeat = { initializePermissions(context) }
)
}
}
- 许可DSL
inline fun Fragment.storagePermissions(
context: Context,
crossinline actionOnGranted: () -> Unit,
crossinline actionOnDeclined: () -> Unit,
crossinline actionRepeat: () -> Unit
) {
when {
Build.VERSION.SDK_INT < Build.VERSION_CODES.Q -> {
if (
ContextCompat.checkSelfPermission(
context, Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
) {
actionOnGranted()
} else {
permission(
Manifest.permission.READ_EXTERNAL_STORAGE
) {
granted = {
actionOnGranted()
}
denied = {
actionRepeat()
}
explained = {
actionOnDeclined()
}
}
}
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
if (
ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_MEDIA_LOCATION
) == PackageManager.PERMISSION_GRANTED) {
Log.d("Storage Permission", "Permission already granted.")
actionOnGranted()
} else {
Log.d("Storage Permission", "No Permission Yet -> Ask for it!")
permissions(
Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.ACCESS_MEDIA_LOCATION
) {
allGranted = {
actionOnGranted()
}
denied = {
Log.d("Storage Permission", "Denied")
actionRepeat()
}
explained = {
Log.d("Storage Permission", "Permanently Denied")
actionOnDeclined()
}
}
}
}
}
}
- 权限扩展
inline fun Fragment.requestPermission(
permission: String,
crossinline granted: (permission: String) -> Unit = {},
crossinline denied: (permission: String) -> Unit = {},
crossinline explained: (permission: String) -> Unit = {}
) {
registerForActivityResult(ActivityResultContracts.RequestPermission()) { result ->
when {
result -> granted.invoke(permission)
shouldShowRequestPermissionRationale(permission) -> denied.invoke(permission)
else -> explained.invoke(permission)
}
}.launch(permission)
}
inline fun Fragment.requestMultiplePermissions(
vararg permissions: String,
crossinline allGranted: () -> Unit = {},
crossinline denied: (List<String>) -> Unit = {},
crossinline explained: (List<String>) -> Unit = {}
) {
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result: MutableMap<String, Boolean> ->
val deniedList = result.filter { !it.value }.map { it.key }
when {
deniedList.isNotEmpty() -> {
val map = deniedList.groupBy { permission ->
if (shouldShowRequestPermissionRationale(permission)) DENIED else EXPLAINED
}
map[DENIED]?.let { denied.invoke(it) }
map[EXPLAINED]?.let { explained.invoke(it) }
}
else -> allGranted.invoke()
}
}.launch(permissions)
}