使用 ViewModel 的 Android Activity Result API:如何引用 ActivityResultRegistry

Android Activity Result API with a ViewModel: how to reference ActivityResultRegistry

提问人:Tim Korelov 提问时间:10/27/2023 更新时间:10/27/2023 访问量:38

问:

我正在使用 Jetpack Compose 和 Dagger-Hilt 制作具有蓝牙功能的应用程序,我的目标之一是能够从应用程序内部发现设备。

令我感到非常惊讶的是,在 SO 或其他地方没有提到这个问题,尽管这个问题似乎很容易遇到:要启动系统活动,例如选择照片、打开设置或提示用户启用蓝牙可发现性,ActivityResultLauncher 应在 ActivityResultRegistry 中注册,然后启动。

由于我只有一个 ComponentActivity,没有 Fragments,正在使用 Jetpack Compose,并且肯定将 UI 与任何逻辑分开,因此只有从 ViewModel 调用此类逻辑才有意义,这就是为什么我很惊讶我没有设法在任何地方找到有关它的信息。不是说即使使用 Fragments 也应该使用 ViewModel 这一事实。

为了实现这一点,我已经在一个单独的应用程序中成功测试了下面的代码(按下按钮并弹出对本机 Android 对话框的调用请求发现,至少在 Android 8 上,在 Android 10 上没有对话框,但它仍然有效),但我仍然不确定此类代码的稳定性:becomeDiscoverable()

class MainViewModel @AssistedInject constructor(
    private val context: Application,
    @Assisted private val registry: ActivityResultRegistry,
) : ViewModel() {

var enableDiscoverableLauncher: ActivityResultLauncher<Intent>? = null
        private set

fun becomeDiscoverable(duration: Int = 20) {
            enableDiscoverableLauncher = registry.register(
                "DISCOVERABLE_ENABLER", ActivityResultContracts.StartActivityForResult()
            ) { }
            val requestCode = 1;
            val discoverableIntent: Intent =
                Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE).apply {
                    putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, duration)
                }
            enableDiscoverableLauncher?.launch(discoverableIntent, ActivityOptionsCompat.makeBasic())
        }

    //@AssistedFactory is below...
}

问题是,由于 ViewModel 的寿命超过了 Activity,我假设在配置更改期间,主要的 ComponentActivity(即 ActivityResultRegistryOwner)将重新创建,如果在该窗口期间调用,则应用程序将崩溃。我无法重现这种行为,但我认为情况确实如此。becomeDiscoverable()

重新创建活动后,viewModel 中对 activityResultRegistry 的引用仍然有效,并且 still 可以成功调用。becomeDiscoverable()

根据“如何在 Jetpack Compose 中获取 ActivityResultRegistry”这个问题的公认答案和我的假设,我可以在组合中的某个点获取并记住,然后使用 Dagger-Hilt 的辅助注入来获取一个视图模型,该模型将包含对 activityResultRegistry 的引用。LocalActivityResultRegistryOwner.current!!.activityResultRegistry

但答案的最后一部分真的让我感到困惑:

我假设您无论如何都在 ComponentActivity 中使用 Compose,因此在访问 ActivityResultRegistryOwner.current 时永远不会收到空引用,因此如果您不想处理可为 null 的类型,则可以使用 !!算子。

怎么会这样?为什么它与 ComponentActivity 特别相关?而且在链接的问题/答案中肯定没有提到 ViewModel,OP 怎么根本不使用 vm?

最重要的是,

在 Jetpack Compose 中实现与最初由 Android 创建并属于主 Activity 的对象的此类引用的交互的正确方法是什么?

android-jetpack-compose android-viewmodel dagger-hilt activity-result-api

评论


答: 暂无答案