kotlin协程_使Kotlin协程无缝采用的5个技巧

吕志诚
2023-12-01

kotlin协程

After successfully adopting coroutines in my prod project I think it is time to share 5 tips on how to make your transition fast and seamless so your project can have a jump start and get full-coroutine-integrated in the shortest time.

在我的产品项目中成功采用协程后,我认为是时候分享5条提示,以使您的过渡快速无缝地进行,以便您的项目可以快速启动并在最短的时间内进行完整的协程集成。

  1. Use libraries built-in support.

    使用库内置支持。

Many libraries have added “out of the box” coroutine support. To avoid creating custom converters and adapters it is a good idea to leverage what libraries provide “for free”.

许多库都添加了“开箱即用”协程支持。 为了避免创建自定义转换器和适配器,最好利用库提供的“免费”内容。

For example, Retrofit (2.6.0 and higher) supports making your network requests suspend functions. Which gives you a nice concise syntax of using it vs having to utilize the “basic” onResponse and onError Retrofit callback structure.

例如,翻新(2.6.0及更高版本)支持使您的网络请求挂起功能。 与使用“基本的” onResponseonError Retrofit回调结构相比 ,这给了您使用它一个简洁的语法。

So this piece of code below

所以下面这段代码

val call = service.getCurrentWeatherData(lat, lon)    
call.enqueue(object : Callback<WeatherResponse> {    
    override fun onResponse(call: Call<WeatherResponse>, response: Response<WeatherResponse>) {      
    }    


    override fun onFailure(call: Call<WeatherResponse>, t: Throwable) {    
    }    
})

will be transformed into this

会变成这个

try {
  val weatherData = service.getCurrentWeatherData(lat, lon)
} catch (t: Throwable) {
  //handle errors here
}

I think it looks pretty good! :)

我认为它看起来不错! :)

Along with Retrofit, Room 2.1 and higher has built-in support for coroutines. You can mark you DAO methods as suspend to allow for concise syntax, nice linear code and making sure they can only be run in your async code blocks. There a very in depth article by Florina Muntenescu here you want to find out more on Room support.

除翻新外,Room 2.1及更高版本还内置了对协程的支持。 您可以将DAO方法标记为暂挂,以使用简洁的语法,精美的线性代码,并确保它们只能在异步代码块中运行。 有一个很由弗洛里纳Muntenescu深入的文章在这里你想了解更多关于房间的支持。

So when making a decision of what library to use check the out-of-the-box support and use the ones that provide it.

因此,在决定使用哪种库时,请检查开箱即用的支持并使用提供该支持的支持。

2. Use default coroutine scopes.

2.使用默认协程范围。

CoroutineScope defines a scope for new coroutines. Every coroutine builder is an extension on CoroutineScope and inherits its coroutineContext to automatically propagate both context elements and cancellation. Every coroutine builder (like launch, async, etc) and every scoping function (like coroutineScope, withContext, etc) provides its own scope.

CoroutineScope定义新协程的范围。 每个协程构建器都是CoroutineScope的扩展,并继承其coroutineContext以自动传播上下文元素和取消。 每个协程生成器(如launchasync等)和每个作用域函数(如coroutineScopewithContext等)都提供自己的作用域。

Manual implementation will slow you down and will be very error-prone. Even the documentation itself advises against that. So use existing scope builders and to make your adoption faster and more robust.

手动执行会降低您的速度,并且容易出错。 甚至文档本身也建议不要这样做。 因此,请使用现有的范围构建器,以使您的采用速度更快,更可靠。

3. Use default coroutine dispatchers.

3.使用默认协程调度程序。

The coroutine context includes a coroutine dispatcher (CoroutineDispatcher) that determines what thread or threads the corresponding coroutine uses for its execution. The coroutine dispatcher can confine coroutine execution to a specific thread, dispatch it to a thread pool, or let it run unconfined.

协程上下文包括一个协程分派器 ( CoroutineDispatcher ),该分派器确定相应协程用于执行的线程。 协程分派器可以将协程执行限制在特定线程中,将其分派到线程池,或者让它不受限制地运行。

All coroutine builders like launch and async accept an optional CoroutineContext parameter that can be used to explicitly specify the dispatcher for the new coroutine and other context elements.

所有协程构建器(如启动异步)都接受一个可选的CoroutineContext参数,该参数可用于为新协程和其他上下文元素显式指定调度程序。

Creating your own custom dispatcher and fine-tuning such things as the thread pool and thread management is of course an option but for a jump start it makes more sense to use one of the default ones that are already optimized for different use cases.

创建您自己的自定义调度程序并微调线程池和线程管理之类的内容当然是一种选择,但是对于快速入门,使用已经针对不同用例进行了优化的默认值之一更有意义。

Here is a snippet from the docs, there is multiple default options.

这是文档的摘录,有多个默认选项。

launch { // context of the parent, main runBlocking coroutine
    println("main runBlocking      : I'm working in thread ${Thread.currentThread().name}")
}
launch(Dispatchers.Unconfined) { // not confined -- will work with main thread
    println("Unconfined            : I'm working in thread ${Thread.currentThread().name}")
}
launch(Dispatchers.Default) { // will get dispatched to DefaultDispatcher 
    println("Default               : I'm working in thread ${Thread.currentThread().name}")
}
launch(Executors.newSingleThreadExecutor().asCoroutineDispatcher()) { // will get its own new thread
    println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}")
}

4. Leverage deep Architecture Components integration.

4.利用深入的架构组件集成。

Fairly recently Google introduced deeper coroutine integration for Architecture Components. That included introducing custom scopes for ViewModel and LifecyleOwner, along with having a LiveData coroutine builder.

相当近期,Google推出了针对架构组件的更深层协程集成 。 这包括引入定制范围为视图模型LifecyleOwner,与具有LiveData协程助洗剂一起。

You can use viewModelScope or viewLifecycleOwner scopes in order to provide out of the box support for auto cancellation and make your coroutines smarter about the app’s lifecycle. This will help you save resources and make the lifecycle management easier in this regard. You will not have to worry about cooperative cancellations or CancellationException in this case as the handling for those is already pre-built for you.

您可以使用viewModelScopeviewLifecycleOwner范围来为自动取消提供开箱即用的支持,并使协程对于应用程序的生命周期更加智能。 在这方面,这将帮助您节省资源并简化生命周期管理。 在这种情况下,您不必担心协作取消或CancellationException ,因为已经为您预先构建了这些操作。

The LiveData builder will provide your with nice syntax and allow to calculate values asynchronously and then update your observers and all that in a concise manner. For example, you might want to retrieve a user’s preferences and provide them to your observer. Just like below you will crate a LiveData that is going to emit your value when computed.

LiveData构建器将为您提供漂亮的语法,并允许异步计算值,然后以简洁的方式更新观察者以及所有这些。 例如,您可能想检索用户的首选项并将其提供给您的观察者。 就像下面一样,您将创建一个LiveData ,该LiveData将在计算时发出您的值。

val user: LiveData<User> = liveData {
    val data = database.loadUser() // loadUser is a suspend function.
    emit(data)
}

5. Check out different builders and suspend/inline functions for concise syntax.

5.签出不同的构建器并暂停/内联函数以获取简洁的语法。

There is multiple coroutine builders, suspend functions and inline functions provided by Kotlin sdk itself that can be used inside coroutines.They can provide nice and concise syntax that you should use to your advantage when adopting coroutines as async code can be hard to follow at times due to its verbose syntax in many cases. The example below uses 4 out of the box solutions (launch (coroutine builder) , repeat (out of the box inline fun), delay (out of the box suspend fun), println (out of the box inline fun)) and you can observe how concise the code is.

Kotlin sdk本身提供了多个协程构建器,暂挂函数和内联函数,可在协程内部使用它们。它们可以提供简洁明了的语法,在采用协程时应利用您的优势,因为有时很难遵循异步代码由于在许多情况下其冗长的语法。 下面的示例使用4种开箱即用的解决方案( 启动 (协程生成器), 重复 (开箱即用的内联功能), 延迟 (开箱即用的暂停功能), println (开箱即用的内联功能)),您可以观察代码的简洁程度。

launch {
    startTime = System.currentTimeMillis()
    repeat(1000){
        delay(6)
    }
    val endTime = System.currentTimeMillis() - startTime
    println("total time= $endTime")
}

And some final thoughts, I personally really love using coroutines on Android. I feel it is a very big step forward from AsyncTask (I know…duh) and even RxJava in some ways. I hope more projects adopt coroutines in the future and they are going to be “demystified” at last. Even though it can be tricky at first — use my tips, make sure to read the docs and you will not look back :)

还有一些最后的想法,我个人真的很喜欢在Android上使用协程。 我觉得这在某种程度上是从AsyncTask(我知道... duh)乃至RxJava迈出的一大步。 我希望将来有更多项目采用协程,并且它们最终将被“揭开神秘面纱”。 即使一开始可能很棘手-请使用我的提示,但请务必阅读文档,并且您不会后退:)

翻译自: https://proandroiddev.com/5-tips-to-make-kotlin-coroutines-adoption-seamless-6590c3d38f9d

kotlin协程

 类似资料: