如何在Kotlin中使用协程每隔几毫秒调用一次函数

时间:2019-09-12 04:09:49

标签: android kotlin coroutine

我想每3秒收到一次网络请求,并在某种情况下将其停止。我使用Coroutine进行网络请求。我使用了postDelayed()方法,它可以正常工作。但是我想在上一个请求的上一个响应完成后发出下一个请求。我使用了delay的{​​{1}}方法,但是UI冻结了,我的应用仍处于无限循环中。使用Coroutine或协程处理此任务?我在此存储库中创建网络请求:

postDelayed

这是我片段中的代码:

     class ProcessRepository  @Inject constructor(private val apiService: ApiService) {
    val _networkState = MutableLiveData<NetworkState>()
    val _networkState_first = MutableLiveData<NetworkState>()

    val completableJob = Job()
    private val coroutineScope = CoroutineScope(Dispatchers.IO + completableJob)

    private val brokerProcessResponse = MutableLiveData<BrokerProcessResponse>()
 fun repeatRequest(processId:String):MutableLiveData<BrokerProcessResponse>{
        var networkState = NetworkState(Status.LOADING, userMessage)
        _networkState.postValue(networkState)
        coroutineScope.launch {
            val request = apiService.repeatRequest(processId, token)
            withContext(Dispatchers.Main) {
                try {
                    val response = request.await()
                    if (response.isSuccessful) {
                        brokerProcessResponse.postValue(response.body())
                        var networkState = NetworkState(Status.SUCCESS, userMessage)
                        _networkState.postValue(networkState)
                    } else {
                        var networkState = NetworkState(Status.ERROR, userMessage)
                        _networkState.postValue(networkState)
                    }
                } catch (e: IOException) {
                    var networkState = NetworkState(Status.ERROR, userMessage)
                    _networkState.postValue(networkState)
                } catch (e: Throwable) {
                    var networkState = NetworkState(Status.ERROR, userMessage)
                    _networkState.postValue(networkState)
                }
            }
            delay(3000) // I only just add this line for try solution using coroutine 
        }

        return brokerProcessResponse
    }

我的解决方案使用 private fun repeatRequest(){ viewModel.repeatRequest(processId).observe(this, Observer { if(it!=null){ process=it.process if(it.process.state== FINDING_BROKER || it.process.state==NONE){ inProgress(true) }else{ inProgress(false) } setState(it!!.process.state!!,it.process) } }) } private fun pullRequest(){ while (isPullRequest){ repeatRequest() } }

postDelayed

3 个答案:

答案 0 :(得分:2)

您的UI死机了,因为您的while循环没有中断:

while (isPullRequest){
     repeatRequest()
}

您正在repeatRequest中异步启动协程并在那里调用delay。这不会暂停pullRequest函数。

您应该在协程中运行循环(repeatRequest函数)。然后,您可以将此协程的job对象提供给调用方,并在需要停止循环时调用cancel

fun repeatRequest(): Job {
    return coroutineScope.launch {  
        while(isActive) {
            //do your request
            delay(3000)
        }
    }
}

//start the loop
val repeatJob = repeatRequest()

//Cancel the loop
repeatJob.cancel()

答案 1 :(得分:2)

对于 Coroutine 的新手

在 Build.gradle 中添加 Coroutine

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'

添加重复作业

    /**
     * start Job
     * val job = startRepeatingJob()
     * cancels the job and waits for its completion
     * job.cancelAndJoin()
     * Params
     * timeInterval: time milliSeconds 
     */
    private fun startRepeatingJob(timeInterval: Long): Job {
        return CoroutineScope(Dispatchers.Default).launch {
            while (NonCancellable.isActive) {
                // add your task here
                doSomething()
                delay(timeInterval)
            }
        }
    }

开始:

  Job myJob = startRepeatingJob(1000L)

停止:

    myJob .cancel()

答案 2 :(得分:1)

看看这个question,它有一个自定义的loop,用法看起来像这样


    // if loop block takes less than 3 seconds, then this loop will iterate after every 3 seconds
    // if loop block takes more than 3 seconds, then this loop will iterate after block is finished
    // loop iterate after block duration or provided minimum interval whichever is maximum
    loop(3.seconds) {
     // make request
     // process response

     stopIf(condition)
    }