如何在kotlin中使用Coroutine每秒调用一个函数

use*_*366 8 android coroutine kotlin

我刚刚创建了一个应用程序,其中我的函数 getdata() 每秒调用一次以从服务器获取新数据,而 updateui() 函数将更新 UI 中的视图我没有在我的应用程序中使用任何异步任务或协程我想这样做请告诉我我怎么能做到这一点。

这是我的代码...

private fun getdata(){
        try {
            val api = RetroClient.getApiService()
            call = api.myJSON
            call!!.enqueue(object : Callback<ProductResponse> {
                override fun onResponse(
                    call: Call<ProductResponse>,
                    response: Response<ProductResponse>
                ) {
                    if (response.isSuccessful) {
                        productList = response.body()!!.data
                        for (list in productList) {
                            if (list.BB.equals("AAA")) {
                                aProductList.add(list)
                            }
                        }
                        if (recyclerView.adapter != null) {
                            eAdapter!!.updatedata(aProductList)
                        }
                        updateui()
                    }
                }

                override fun onFailure(call: Call<ProductResponse>, t: Throwable) {
                    println("error")
                }
            })
        } catch (ex: Exception) {
        } catch (ex: OutOfMemoryError) {
        }
Handler().postDelayed({
            getdata()
        }, 1000)
}


private fun updateui() {
        try {
            //some code to handel ui
 } catch (e: NumberFormatException) {

        } catch (e: ArithmeticException) {

        } catch (e: NullPointerException) {

        } catch (e: Exception) {

        }
    }
Run Code Online (Sandbox Code Playgroud)

Hit*_*ahu 8

对于那些刚接触协程的人

在 Build.gradle 中添加协程

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'
Run Code Online (Sandbox Code Playgroud)

创建重复作业

    /**
     * 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)
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

开始:

  Job myJob = startRepeatingJob(1000L)
Run Code Online (Sandbox Code Playgroud)

停止:

    myJob .cancel()
Run Code Online (Sandbox Code Playgroud)

  • `NonCancellable.isActive` 现在是一个内部 API,但是您仍然可以与注释一起使用。 (2认同)

Rob*_*bCo 6

使用协程每秒运行一个函数:

val scope = MainScope() // could also use an other scope such as viewModelScope if available
var job: Job? = null

fun startUpdates() {
    stopUpdates()
    job = scope.launch {
        while(true) {
            getData() // the function that should be ran every second
            delay(1000)
        }
    }
}

fun stopUpdates() {
    job?.cancel()
    job = null
}
Run Code Online (Sandbox Code Playgroud)

但是,如果getData()启动网络请求而不等待其完成,这可能不是一个好主意。该函数将在完成后一秒钟被调用,但由于网络请求是异步完成的,因此可能被调度得太多。
例如,如果网络请求需要 5 秒,那么它会在第一个甚至完成之前再启动 4 次!

为了解决这个问题,你应该找到一种方法来暂停协程,直到网络请求完成。
这可以通过使用阻塞api来完成,然后传递Dispatchers.IOlaunch函数以确保它在后台线程上完成。

或者,您可以使用suspendCoroutine将基于回调的 api 转换为挂起的 api。


但是,总而言之,改变这一切可能太麻烦了。就放:

Handler().postDelayed({
    getData()
}, 1000) 
Run Code Online (Sandbox Code Playgroud)

在您的updateui功能结束时并完成它。
这样它会在完成后一秒被安排。


vig*_*esh 5

不建议每秒访问服务器。如果您需要连续获取数据,请尝试使用套接字。因为有时您的服务器需要超过几秒钟才能响应您的请求。那么你的所有请求都将排在队列中......如果你仍然需要尝试这个。

fun repeatFun(): Job {
    return coroutineScope.launch {  
        while(isActive) {
            //do your network request here
            delay(1000)
        }
    }
}

//start the loop
val repeatFun = repeatRequest()

//Cancel the loop
repeatFun.cancel()
Run Code Online (Sandbox Code Playgroud)


nil*_*lsi 5

我最终用扩展函数做了这样的事情:

fun CoroutineScope.launchPeriodicAsync(repeatMillis: Long, action: () -> Unit) = this.async {
  while (isActive) {
    action()
    delay(repeatMillis)
  }
}
Run Code Online (Sandbox Code Playgroud)

然后这样称呼它:

val fetchDatesTimer = CoroutineScope(Dispatchers.IO)
  .launchPeriodicAsync(TimeUnit.MINUTES.toMillis(1)) {
    viewModel.fetchDeliveryDates()
  }
Run Code Online (Sandbox Code Playgroud)

并像这样取消它:

fetchDatesTimer.cancel()
Run Code Online (Sandbox Code Playgroud)