如何修复Kotlin中Attempting to launch an unregistered ActivityResultLauncher崩溃
Google InAppUpdate 集成崩溃问题排查
问题描述
我在应用中集成了Google的InAppUpdate功能,部分设备出现崩溃但无法复现。Firebase捕获到的崩溃信息如下:
Fatal Exception: java.lang.IllegalStateException: Attempting to launch an unregistered ActivityResultLauncher with contract c.c@5d5894e and input androidx.activity.result.k@c156a6f. You must ensure the ActivityResultLauncher is registered before calling launch()
我的MainActivity代码如下,activityResultLauncher为全局变量,在onCreate方法中检查应用更新,请问有人遇到过该问题吗?
class MainActivity : AppCompatActivity() { private lateinit var appUpdateManager: AppUpdateManager override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val toolbar = findViewById<MaterialToolbar>(R.id.toolbar) setSupportActionBar(toolbar) appUpdateManager = AppUpdateManagerFactory.create(applicationContext) appUpdateManager.registerListener(installStateUpdatedListener) checkForAppUpdates() } private val activityResultLauncher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result -> if (result.resultCode != RESULT_OK) { Toast.makeText(this, R.string.something_went_wrong, Toast.LENGTH_SHORT).show() } } private val installStateUpdatedListener = InstallStateUpdatedListener { state -> if (state.installStatus() == InstallStatus.DOWNLOADED) { popupSnackbarForCompleteUpdate() } } private fun checkForAppUpdates() { val appUpdateInfoTask = appUpdateManager.appUpdateInfo appUpdateInfoTask.addOnSuccessListener { appUpdateInfo -> if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) { appUpdateManager.startUpdateFlowForResult( appUpdateInfo, activityResultLauncher, AppUpdateOptions.newBuilder(AppUpdateType.FLEXIBLE).build() ) } } } private fun popupSnackbarForCompleteUpdate() { Snackbar.make(findViewById(R.id.cordmain), R.string.update_downloaded, Snackbar.LENGTH_INDEFINITE) .setAction(R.string.restart) { appUpdateManager.completeUpdate() } .show() } }
问题原因
崩溃核心原因是ActivityResultLauncher未完成注册就被调用launch方法:
- Kotlin类属性初始化顺序中,全局的
activityResultLauncher虽然声明在onCreate上方,但如果checkForAppUpdates里的appUpdateInfoTask回调因缓存数据快速返回,此时Launcher可能还未完成注册就被传入startUpdateFlowForResult。 - 未注销
appUpdateManager的监听器,当Activity被系统销毁重建时,旧监听器可能触发回调,而新的Launcher尚未初始化完成。
解决办法
1. 调整初始化顺序,确保Launcher优先注册
将activityResultLauncher的初始化移到onCreate内部,早于checkForAppUpdates调用:
class MainActivity : AppCompatActivity() { private lateinit var appUpdateManager: AppUpdateManager private lateinit var activityResultLauncher: ActivityResultLauncher<IntentSenderRequest> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val toolbar = findViewById<MaterialToolbar>(R.id.toolbar) setSupportActionBar(toolbar) // 先初始化ActivityResultLauncher activityResultLauncher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result -> if (result.resultCode != RESULT_OK) { Toast.makeText(this, R.string.something_went_wrong, Toast.LENGTH_SHORT).show() } } appUpdateManager = AppUpdateManagerFactory.create(applicationContext) appUpdateManager.registerListener(installStateUpdatedListener) checkForAppUpdates() } // 其余代码保持不变 }
2. 注销AppUpdateManager监听器
在onDestroy中注销监听器,避免旧回调触发:
override fun onDestroy() { super.onDestroy() appUpdateManager.unregisterListener(installStateUpdatedListener) }
3. 增加Launcher初始化状态检查(可选)
在调用更新流程前,确保Launcher已初始化:
private fun checkForAppUpdates() { val appUpdateInfoTask = appUpdateManager.appUpdateInfo appUpdateInfoTask.addOnSuccessListener { appUpdateInfo -> if (::activityResultLauncher.isInitialized && appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) { appUpdateManager.startUpdateFlowForResult( appUpdateInfo, activityResultLauncher, AppUpdateOptions.newBuilder(AppUpdateType.FLEXIBLE).build() ) } } }
内容的提问来源于stack exchange,提问作者Yasiru Nayanajith
相关产品推荐
相关产品推荐

