Android中ActivityResultLauncher未注册异常求助
解决ActivityResultLauncher未注册的IllegalStateException
问题根源
异常触发于Google登录异步任务的回调中调用launch():当点击按钮发起登录请求后,若Activity因配置变更(如横竖屏切换)销毁重建,异步回调会持有旧Activity实例的ActivityResultLauncher引用,而旧实例的launcher已被系统注销,此时调用launch()就会触发未注册异常——你在点击事件里的非空检查只覆盖了同步场景,没处理异步回调的生命周期错位问题。
具体解决办法
办法1:用弱引用持有Activity,回调中检查状态
将Activity的引用改为弱引用,在异步回调中先确认Activity处于活跃状态,再使用当前实例的launcher:
class LoginActivity : AppCompatActivity() { private lateinit var resultLauncherForGmailSignIn: ActivityResultLauncher<Intent> // 用弱引用持有Activity private val activityWeakRef = WeakReference(this) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_login) // 注册launcher resultLauncherForGmailSignIn = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> result.data?.let { loginViewModel.signInWithGmail(it) } } findViewById<Button>(R.id.myButton).setOnClickListener { // 发起Google登录异步请求 val signInIntent = GoogleSignIn.getClient(this, gso).signInIntent GoogleSignIn.getClient(this, gso).silentSignIn() .addOnCompleteListener { task -> val currentActivity = activityWeakRef.get() // 检查Activity是否活跃且launcher已初始化 if (currentActivity != null && !currentActivity.isFinishing && !currentActivity.isDestroyed) { if (currentActivity::resultLauncherForGmailSignIn.isInitialized) { currentActivity.resultLauncherForGmailSignIn.launch(signInIntent) } } } } } }
办法2:用ViewModel+LiveData实现生命周期安全的launch
将launch操作通过LiveData通知Activity,确保只有在Activity活跃时才执行:
- 在LoginViewModel中定义LiveData:
class LoginViewModel : ViewModel() { // 用于通知Activity发起登录跳转 private val _launchGmailSignIn = MutableLiveData<Intent?>() val launchGmailSignIn: LiveData<Intent?> = _launchGmailSignIn fun triggerGmailSignIn(intent: Intent) { _launchGmailSignIn.postValue(intent) } }
- 在LoginActivity中观察LiveData,处理launch:
class LoginActivity : AppCompatActivity() { private lateinit var resultLauncherForGmailSignIn: ActivityResultLauncher<Intent> private val loginViewModel by viewModels<LoginViewModel>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_login) // 注册launcher resultLauncherForGmailSignIn = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> result.data?.let { loginViewModel.signInWithGmail(it) } } // 观察LiveData,在Activity活跃时执行launch loginViewModel.launchGmailSignIn.observe(this) { intent -> intent?.let { resultLauncherForGmailSignIn.launch(it) } } findViewById<Button>(R.id.myButton).setOnClickListener { val signInIntent = GoogleSignIn.getClient(this, gso).signInIntent GoogleSignIn.getClient(this, gso).silentSignIn() .addOnCompleteListener { task -> // 通知ViewModel触发跳转 loginViewModel.triggerGmailSignIn(signInIntent) } } } }
办法3:在Activity销毁时取消异步回调
在Activity的onDestroy()方法中移除异步任务的回调,避免在Activity销毁后执行launch:
class LoginActivity : AppCompatActivity() { private lateinit var resultLauncherForGmailSignIn: ActivityResultLauncher<Intent> // 保存异步任务引用,用于取消回调 private var signInTask: Task<GoogleSignInAccount>? = null // 保存回调引用 private val signInCompleteListener = OnCompleteListener<GoogleSignInAccount> { task -> // 执行launch逻辑 if (this::resultLauncherForGmailSignIn.isInitialized) { resultLauncherForGmailSignIn.launch(signInIntent) } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_login) resultLauncherForGmailSignIn = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> result.data?.let { loginViewModel.signInWithGmail(it) } } findViewById<Button>(R.id.myButton).setOnClickListener { val signInIntent = GoogleSignIn.getClient(this, gso).signInIntent signInTask = GoogleSignIn.getClient(this, gso).silentSignIn() signInTask?.addOnCompleteListener(signInCompleteListener) } } override fun onDestroy() { super.onDestroy() // 移除回调,避免Activity销毁后执行 signInTask?.removeOnCompleteListener(signInCompleteListener) } }
内容的提问来源于stack exchange,提问作者Andyson
相关产品推荐
相关产品推荐

