Kotlin Android开发如何等待onCreate内调用的两个函数执行完再运行后续代码
问题原因
你遇到的执行时序异常是因为observeEmail()、observePassword()两个方法内部是异步逻辑:调用observe方法仅完成观察者的注册,实际的回调逻辑会被系统异步调度执行,所以onCreate中的同步后续代码会先运行,观察者回调的打印才会输出。
实现方案
核心思路是不要用阻塞方式等待(会卡住主线程触发ANR),而是通过状态监听,等两个异步逻辑都执行完成后再触发后续代码。
方案1:计数器实现(改造成本最低)
通过计数器记录两个观察者的执行状态,全部执行完成后触发后续逻辑:
- 首先定义计数器和状态检查方法
// 初始值为2,对应两个需要等待的观察函数 private val initTaskCounter = AtomicInteger(2) private fun tryRunPostInit() { if (initTaskCounter.decrementAndGet() == 0) { // 此处放置你原本onCreate中需要等两个函数执行完再跑的后续代码 Log.d("Init", "两个观察函数均执行完成,后续逻辑开始运行") } }
- 在两个观察函数的回调末尾各调用一次状态检查方法
private fun observeEmail() { userManager.emailLiveData.observe(this) { email -> // 你原本的业务逻辑 Log.d("observe", "email更新完成") // 新增调用 tryRunPostInit() } } private fun observePassword() { userManager.passwordLiveData.observe(this) { pwd -> // 你原本的业务逻辑 Log.d("observe", "password更新完成") // 新增调用 tryRunPostInit() } }
方案2:MediatorLiveData合并数据源(LiveData技术栈适用)
如果你的数据是通过LiveData提供,可以用MediatorLiveData合并两个数据源,都拿到结果后触发后续逻辑:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) userManager = UserManager(this) val emailLiveData = userManager.getEmailLiveData() val pwdLiveData = userManager.getPasswordLiveData() val initMediator = MediatorLiveData<Unit>() var hasEmail = false var hasPwd = false initMediator.addSource(emailLiveData) { // 处理email更新逻辑 hasEmail = true if (hasEmail && hasPwd) { initMediator.value = Unit } } initMediator.addSource(pwdLiveData) { // 处理password更新逻辑 hasPwd = true if (hasEmail && hasPwd) { initMediator.value = Unit } } initMediator.observe(this) { // 执行后续逻辑 doPostInitWork() // 用完移除观察者,避免后续数据变更重复触发 initMediator.removeObservers(this) } }
方案3:Flow combine操作符(协程技术栈适用)
如果你的数据是通过Flow提供,可以用combine合并两个流,拿到首次有效结果后执行后续逻辑:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) userManager = UserManager(this) lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.CREATED) { combine( userManager.emailFlow, userManager.passwordFlow ) { email, pwd -> // 校验两个数据是否都有效 email != null && pwd != null }.first { isAllReady -> // 等待两个数据都有效后结束等待 isAllReady } // 此处执行后续逻辑 doPostInitWork() } } }
注意事项
- 禁止在主线程调用
CountDownLatch.await()、Thread.sleep()等阻塞方法等待异步逻辑执行完成,会导致主线程卡死触发ANR。 - 如果观察的数据源会持续推送更新,在首次触发后续逻辑后需要及时移除不需要的观察者,避免重复执行逻辑。
内容的提问来源于stack exchange,提问作者traktor
相关产品推荐
相关产品推荐

