簡體   English   中英

如何在kotlin中使用協程每隔幾毫秒調用一個函數

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

我想每 3 秒收到一次網絡請求,並在某些情況下停止它。 我正在使用Coroutine進行網絡請求。我使用了postDelayed()方法並且它工作正常。 但是我想在上一個請求的上一個響應完成后發出下一個請求。我使用了Coroutine delay方法,但是 UI 已經凍結並且我的應用程序仍然處於無限循環中。如何使用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

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

您的用戶界面凍結,因為您的while循環不間斷地運行:

while (isPullRequest){
     repeatRequest()
}

您在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()

對於那些不熟悉 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()

看看這個問題,它有一個自定義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