如何在Kotlin中使用协程每秒调用一个函数

ldfqzlk8  于 2022-12-13  发布在  Kotlin
关注(0)|答案(6)|浏览(357)

我刚刚创建了一个应用程序,我的函数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) {

        }
    }
afdcj2ne

afdcj2ne1#

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

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
}

然而,如果getData()只 * 启动 * 一个网络请求,而不等待它完成,这可能不是一个好主意。函数将在它完成后一秒钟被调用,但因为网络请求是异步完成的,它可能被调度得太多。
例如,如果网络请求需要5秒,则在第一个请求完成之前,它将启动4次以上!
要解决这个问题,您应该找到一种方法来挂起协程,直到网络请求完成。
这可以通过使用一个 blocking API来完成,然后将Dispatchers.IO传递给launch函数,以确保它在后台线程上完成。
或者,您可以使用suspendCoroutine将基于回调的API转换为挂起的api。

更新-生命周期范围

在具有Android生命周期的组件中,您可以使用以下代码来自动重复UI更新:

fun startUpdates() {
    val lifecycle = this // in Activity
    val lifecycle = viewLifecycleOwner // in Fragment

    lifecycle.lifecycleScope.launch {
        lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
            // this block is automatically executed when moving into
            // the started state, and cancelled when stopping.
            while (true) {
                getData() // the function to repeat
                delay(1000)
            }
        }
    }
}

此程式码需要目前的androidx.lifecycle:lifecycle-runtime-ktx相依性。
上面关于getData()中的异步、阻塞或挂起代码的注解仍然适用。

mftmpeh8

mftmpeh82#

不建议每秒钟都访问服务器。如果您需要连续获取数据,请尝试使用套接字。因为有时服务器需要几秒钟以上的时间来响应您的请求。然后,您的所有请求都将在队列中。如果您仍需要尝试使用此方法,请尝试使用套接字。

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

ufj5ltwl3#

对于那些不熟悉Coroutine的人

在Build.gradle中添加协同程序

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()
3hvapo4f

3hvapo4f4#

最后我用一个扩展函数完成了如下操作:

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

那么就叫它:

val fetchDatesTimer = CoroutineScope(Dispatchers.IO)
  .launchPeriodicAsync(TimeUnit.MINUTES.toMillis(1)) {
    viewModel.fetchDeliveryDates()
  }

然后像这样取消它:

fetchDatesTimer.cancel()
vwoqyblh

vwoqyblh5#

我在MainViewModel内的Kotlin中的解决方案

fun apiCall() {
       viewModelScope.launch(Dispatchers.IO) {
         while(isActive) {
            when(val response = repository.getServerData()) {
                is NetworkState.Success -> {
                    getAllData.postValue(response.data)
                }
                is NetworkState.Error -> this@MainViewModel.isActive = false
            }

            delay(1000)
        }
    }
}

sealed class NetworkState<out R> {
    data class Success<out T>(val data: T): NetworkState<T>()
    data class Error(val exception: String): NetworkState<Nothing>()
    object Loading: NetworkState<Nothing>()
}
7uhlpewt

7uhlpewt6#

我的解决方案是一次性运行一个代码后,检查某个东西是否成功,并定期检查,功能是:

fun CoroutineScope.launchPeriodic(repeatMillis: Long, action: () -> Unit) : Job {
            return launch {
                while (!enabled) {
                    action()
                    delay(repeatMillis)
                }
            }
        }

并在此处启动周期性函数(其中action每2秒运行一次),当启用某些内容并运行某些代码时,该函数将自动结束:

CoroutineScope(Dispatchers.IO).launchPeriodic(TimeUnit.SECONDS.toMillis(2)) {
           if(checkIfSomethingIsEnabledCodeIsHere) {
               enabled = true
               //some code here to run when it is enabled
           }
        }

相关问题