【问题标题】:Kotlin wait for async with coroutineKotlin 等待与协程异步
【发布时间】:2020-10-21 17:59:32
【问题描述】:

我想在实例化 phoneViewModel 和 ScanViewModel 时打开一个新活动。它们通过调用异步函数 InitialRead() 来实例化。我正在记录每一步,atm 它们被记录为 done3 => done2 => done1

我希望它们按以下顺序排列: 完成1 => 完成2 => 完成3

我有以下代码:

class MainBusinessActivity : AppCompatActivity() {

private lateinit var scanViewModel: ScanViewModel
private lateinit var phoneViewModel: PhoneViewModel

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main_business)
}

private fun startEntitySetListActivity() = GlobalScope.async {
    val sapServiceManager = (application as SAPWizardApplication).sapServiceManager
    sapServiceManager?.openODataStore {
        phoneViewModel =  ViewModelProvider(this@MainBusinessActivity).get(PhoneViewModel::class.java).also {it.initialRead{Log.e("done", "done1")}}
        scanViewModel = ViewModelProvider(this@MainBusinessActivity).get(ScanViewModel::class.java).also {it.initialRead{Log.e("done", "done2")}}
    }
}

override fun onResume() {
    super.onResume()
    //startEntitySetListActivity()
    runBlocking {
        startEntitySetListActivity().await()
        val intent = Intent(this@MainBusinessActivity, HomeActivity::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
        Log.e("done", "done3")
        startActivity(intent)
    }
}

}

我做错了什么?有人可以更正我的代码吗?

【问题讨论】:

    标签: android kotlin kotlin-coroutines


    【解决方案1】:

    切勿在 Android 应用中使用 runBlockingrunBlocking 完全违背了使用协程的目的,并可能导致 ANR。你也可能永远不应该使用GlobalScope,这会导致 UI 泄漏。您可能需要它来执行某种长时间运行的任务,这些任务在放入服务中没有意义,但不依赖任何 UI 组件,但我想不出任何示例

    您也不应该在后台实例化您的 ViewModel。这应该在onCreate() 中完成。

    使这个函数成为一个挂起函数,它可以在返回之前同时分解后台的两个任务。

    使用lifecycleScope 启动您的协程。

    假设sapServiceManager?.openODataStore 是一个接受回调的异步任务,您需要将其包装在suspendCoroutine 中。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main_business)
        phoneViewModel = ViewModelProvider(this@MainBusinessActivity).get(PhoneViewModel::class.java)
        scanViewModel = ViewModelProvider(this@MainBusinessActivity).get(ScanViewModel::class.java)
    }
    
    private suspend fun startEntitySetListActivity() = coroutineScope {
        val sapServiceManager = (application as SAPWizardApplication).sapServiceManager
        sapServiceManager ?: return
        suspendCoroutine<Unit> { continuation ->
            sapServiceManager.openODataStore { continuation.resume(Unit) }
        }
        listOf(
            launch {
                phoneViewModel.initialRead{Log.e("done", "done1")}
            },
            launch {
                scanViewModel.initialRead{Log.e("done", "done2")}
            }
        ).joinAll()
    }
    
    override fun onResume() {
        super.onResume()
        lifecycleScope.launch {
            startEntitySetListActivity()
            val intent = Intent(this@MainBusinessActivity, HomeActivity::class.java)
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
            Log.e("done", "done3")
            startActivity(intent)
        }
    }
    

    【讨论】:

    • 感谢您的评论,但我收到有关启动和生命周期范围的未解决参考。我需要声明它们还是导入它们?
    • 也许你缺少对androidx.fragment:fragment-ktx的构建依赖?
    • 我也错过了 coroutineScope 包装器。刚刚在上面修好了。
    • 谢谢,剩下的唯一问题是我的视图模型必须在 openODataStore{HERE} 中实例化。否则我无法创建类 PhoneViewModel 的实例
    • 我不明白那个类或函数是什么,或者当你没有从那个 lambda 向 ViewModel 工厂传递任何东西时,你的 ViewModel 实例化如何需要它。
    猜你喜欢
    • 2022-01-18
    • 2019-02-21
    • 2021-10-27
    • 1970-01-01
    • 2020-12-13
    • 1970-01-01
    • 1970-01-01
    • 2013-02-15
    相关资源
    最近更新 更多