Jetpack Compose和Dagger-Hilt中ViewModel使用ActivityResultRegistry的正确方案
背景
我正在使用Jetpack Compose和Dagger-Hilt开发一款具备蓝牙功能的应用,核心需求之一是在应用内开启设备可发现性。这类调用系统Activity(比如请求蓝牙可发现性、选择照片、打开设置)的场景,常规流程是将ActivityResultLauncher注册到ActivityResultRegistry后再启动,但我发现相关讨论资料极少。
我的项目仅使用单个ComponentActivity、无Fragment,且遵循UI与逻辑分离的原则,自然希望将开启可发现性的逻辑放在ViewModel中处理,但相关资料十分匮乏——即便使用Fragment,这类逻辑也应该借助ViewModel实现。
现有测试实现(可运行但存稳定性疑虑)
我编写了一段测试代码,点击按钮调用becomeDiscoverable()后,Android 8会弹出原生对话框请求开启可发现性,Android 10无对话框但功能正常,但我不确定这段代码的稳定性:
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 discoverableIntent: Intent = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE).apply { putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, duration) } enableDiscoverableLauncher?.launch(discoverableIntent, ActivityOptionsCompat.makeBasic()) } //@AssistedFactory is below... }
现有疑虑
ViewModel的生命周期长于Activity,我担心配置变更时,作为ActivityResultRegistryOwner的ComponentActivity重建后,此时调用becomeDiscoverable()会导致崩溃——虽然目前未复现该问题,但存在理论风险。不过实际测试中,Activity重建后ViewModel中activityResultRegistry的引用仍有效,becomeDiscoverable()仍能成功调用。
对参考方案的困惑
根据某Stack Overflow问题的Accepted Answer,我可以在Compose组合中获取并记住LocalActivityResultRegistryOwner.current!!.activityResultRegistry,再通过Dagger-Hilt的辅助注入获取持有该引用的ViewModel。但答案中的这段内容让我困惑:
I am assuming that you are using Compose inside a ComponentActivity anyway, so you will never receive a null reference when accessing ActivityResultRegistryOwner.current, so if you do not want to deal with a nullable type, you can use the !! operator.
我有两点疑问:
- 为什么仅在ComponentActivity中,
LocalActivityResultRegistryOwner.current不会为null? - 该问题的提问者为何不使用ViewModel来处理相关逻辑?
核心问题
在Jetpack Compose中,如何正确实现与Activity所属的Android原生对象(如ActivityResultRegistry)的交互?
内容的提问来源于stack exchange,提问作者Tim Korelov

