【问题标题】:How to avoid navigating to next until Task is complete?如何避免在任务完成之前导航到下一个?
【发布时间】:2021-04-16 12:38:18
【问题描述】:

我在其中一个片段上关注了clickListener

 binding.btnCamera.setOnClickListener {
        val photo = takePhoto()
        
        val prediction = MachineLearning().predict(photo)
       
        val action = FirstFragmentDirections.actionFirstToSecond(prediction)

        findNavController().navigate(action)
}

MachinLearing.kt predict() 函数如下所示,其中包含一个异步执行的任务。

fun predict(photo: Bitmap): Boolean {

    val conditions = CustomModelDownloadConditions.Builder()
        .requireWifi()
        .build()

    FirebaseModelDownloader.getInstance()
        .getModel(modelName, DownloadType.LOCAL_MODEL_UPDATE_IN_BACKGROUND, conditions)
        .addOnSuccessListener { customModel ->
           ...
        }
        .addOnFailureListener{
           ...
        }
    ...
}

我想停止导航到下一个片段,直到 predict() 中的 Task 完成。

由于Task 的异步特性。 Task 在片段导航之前完成不太可能发生。如果片段导航发生,那么onDestroy() 将在当前片段中被调用,导致MachineLearning 对象被垃圾回收,所以Task 完成根本不会发生。

那么我怎么能在片段导航之前等待任务完成呢?

【问题讨论】:

  • 最初,您应该将回调传递给predict,该回调会在工作完成时触发。但是当您使用 Kotlin 时,我建议您改用挂起函数。
  • @user158 我最好的猜测是因为人们看到了数百个异步问题,这些问题不是问题,但对异步编程的工作原理缺乏了解。检查我的答案,它可能会帮助你。
  • @user158 为什么混合主题是一个正当的借口?
  • @user158 你不知道主题A但你提到主题B,提到主题B并不能弥补不知道A

标签: android kotlin task


【解决方案1】:

addOnCompleteListeneraddOnFailureListener 方法是回调。这意味着是异步的,因此无论predict 返回的方法是什么,它都可能在触发这些方法之前或之后发生。有两种选择:添加另一个回调或将其转换为挂起。

回调:

fun predict(photo: Bitmap, predictionDelegate: (Boolean) -> Unit) {
    //...
    addOnCompleteListener { model ->
        //do your thing and then call the callback
        predictionDelegate.invoke(yourCalculatedBoolean)
    }
    .addOnFailureListener...//do the same

}

然后调用它:

MachineLearning().predict(photo) { prediction ->
    val action = FirstFragmentDirections.actionFirstToSecond(prediction)

    findNavController().navigate(action)
}

另一种选择是让它暂停:

suspend fun predict(): Boolean() {
    val deferred = CompletableDeferred<Boolean()
    //your thing
    enter code here
    .addOnSuccessListener { model ->
        //do your thing and then update the defferred
        deferred.complete(yourCalculatedBoolean)
    }
    .addOnFailureListener...//do the same

    return deferred.await()
}

然后调用它

lifecycleScope.launch {
    val prediction = MachineLearning().predict(photo)
       
    val action = FirstFragmentDirections.actionFirstToSecond(prediction)

    findNavController().navigate(action)
}

由于绑定,我假设您在 FragmentActivity 中,所以您应该拥有 lifecycleScope

【讨论】:

  • @user158 再看看
猜你喜欢
  • 1970-01-01
  • 2014-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多