Android-Kotlin:开始和停止循环执行任务的最佳方式,从结束后每隔几秒重复一次

Android-Kotlin: best way to start and stop a cyclic execution of a task, repeating it every few seconds from its conclusion

我的目标:

在片段视图中,我有一个按钮,当按下一次时,它会在 viewModel 中启动一个方法,该方法循环调用一个挂起函数,从结束后每隔几秒重复一次。再次按下按钮停止此循环。

我的做法:

片段中 我设置了按钮的 onclicklistener

binding.demoButton.setOnClickListener {
            viewModel.toggleDemo()
        }

viewModel 中:

 private var startDemo : Boolean = false //I need to know whether to start the loop or stop it
 private var isBusy : Boolean = false //I need to know if my task is running or finished

fun toggleDemo(){
        val oldValue : Boolean = startDemo
        val newValue = !oldValue
        startDemo = newValue
        if(startDemo){
            saveLogLine("** start demo **") //method that passes some log strings to the fragment
            startDemo()
        }else{
            saveLogLine("NO start demo!!")
        }
    }

private fun startDemo(){
        GlobalScope.launch(Dispatchers.IO) {
            saveLogLineAsync("before while loop")
            while(startDemo){
                if(!isBusy){
                    isBusy = true
                    Handler(Looper.getMainLooper()).postDelayed({
                        runBlocking(Dispatchers.IO) {
                            saveLogLineAsync("inside runBlocking")
                            initDemo()
                        }
                        isBusy = false
                        saveLogLineAsync("inside handler")
                    }, 5000)
                }

            }
            saveLogLineAsync("after while loop")
        }
    }

    private suspend fun initDemo(){  //my task
      
    }

有没有更优雅的方法来做到这一点?

我本来想使用 Service () 或 BroadcastReceiver () 但在这两种情况下我不知道如何让它们与片段或 viewModel 通信(更准确地说,它们应该能够使用2 种方法 'saveLogLineAsync' 和 'intDemo')

您可以这样简化您的代码:

    private var demoRunning = false
    private var demoJob: Job? = null

    fun toggleDemo() {
        if (!demoRunning) {
            startDemo()
        } else {
            demoJob?.cancel()
        }
        demoRunning = !demoRunning
    }

    private fun startDemo() {
        demoJob = viewModelScope.launch(Dispatchers.IO) {
            while (true) {
                initDemo()
                delay(5000)
            }
        }
    }

    private suspend fun initDemo() {  //my task
        Log.e("INIT DEMO", "initDemo Ran")
    }