简体   繁体   English

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

[英]how to call a function every several millisecond using coroutine in kotlin

I want to get request to network every 3 seconds and in the some condition stop it.我想每 3 秒收到一次网络请求,并在某些情况下停止它。 I am using Coroutine for network request.I used postDelayed() method and it work correctly.我正在使用Coroutine进行网络请求。我使用了postDelayed()方法并且它工作正常。 But I want to make the next request after previous response of the previous request is complete.I used delay method of Coroutine but But The UI have freeze and My app is remained in the infinite loop .How to handle this task using postDelayed or coroutine?但是我想在上一个请求的上一个响应完成后发出下一个请求。我使用了Coroutine delay方法,但是 UI 已经冻结并且我的应用程序仍然处于无限循环中。如何使用postDelayed或协程处理此任务? I create network request in the this repository:我在这个存储库中创建网络请求:

     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
    }

And this is code in my fragment:这是我的片段中的代码:

     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()
        }

    }

And My solution using postDelayed :我的解决方案使用postDelayed

     private fun init() {
        mHandler = Handler()
}


private fun pullRequest() {

        mRunnable = Runnable {

            repeatRequest()
            Log.e(TAG, "in run")
            mHandler.postDelayed(
                mRunnable,
                3000
            )
        }

        mHandler.postDelayed(
            mRunnable,
            3000
        )
    }
 private fun cancelRequest() {
    viewModel.cancelRequest(processId).observe(this, Observer {
        if (it != null) {
            processShareViewModel.setProcess(it.process)
            mHandler.removeCallbacks(mRunnable)
            mHandler.removeCallbacksAndMessages(null)

            isPullRequest = false
            if (findNavController().currentDestination?.id == R.id.requstBrokerFragment) {
                val nextAction = RequstBrokerFragmentDirections.actionRequstBrokerFragmentToHomeFragment()
                // nextAction.keyprocess = it.process
                findNavController().navigate(nextAction)
            }

        }
        Log.e(TAG, "response request borker: " + it.toString())
    })
}


 override fun onDestroy() {
        super.onDestroy()
        // Stop the periodic task
        isPullRequest = false
        mHandler.removeCallbacks(mRunnable)
        mHandler.removeCallbacksAndMessages(null)
    }

Your UI is freezing because your while loop is running without a break:您的用户界面冻结,因为您的while循环不间断地运行:

while (isPullRequest){
     repeatRequest()
}

Your are starting a coroutine asynchronously in repeatRequest and invoke delay there.您在repeatRequest异步启动协程并在repeatRequest调用delay This will not suspend the pullRequest function.这不会挂起pullRequest函数。

You should run the loop within the coroutine ( repeatRequest function).您应该在协程( repeatRequest函数)中运行循环。 Then you can give the job object of this coroutine to the caller and invoke cancel whenever you like to stop the loop:然后,您可以将此协程的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()

For those who are new to Coroutine对于那些不熟悉 Coroutine 的人

add Coroutine in Build.gradle在 Build.gradle 中添加 Coroutine

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

Add a repeating Job添加重复作业

    /**
     * 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)
            }
        }
    }

To start:开始:

  Job myJob = startRepeatingJob(1000L)

To Stop:停止:

    myJob .cancel()

Have a look at this question , it has a custom loop and it's usage can look like this看看这个问题,它有一个自定义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)
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM