如何避免在任务完成之前导航到下一个?

How to avoid navigating to next until Task is complete?

我关注了其中一个片段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 完成根本不会发生。

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

方法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.