Kotlin协程使用

作者: 奔跑吧李博 | 来源:发表于2020-10-09 16:19 被阅读0次
什么是Kotlin协程

协程通过将复杂性放入库来简化异步编程。程序的逻辑可以在协程中顺序地表达,而底层库会为我们解决其异步性。该库可以将用户代码的相关部分包装为回调、订阅相关事件、在不同线程(甚至不同机器)上调度执行,而代码则保持如同顺序执行一样简单。

协程就像非常轻量级的线程。线程是由系统调度的,线程切换或线程阻塞的开销都比较大。而协程依赖于线程,但是协程挂起时不需要阻塞线程,几乎是无代价的,协程是由开发者控制的。所以协程也像用户态的线程,非常轻量级,一个线程中可以创建任意个协程。

引用库
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1"
开启协程
  1. runBlocking
    fun runBlocking() = runBlocking {
        repeat(5) {
            Log.i("minfo", "协程执行$it,当前线程id:${Thread.currentThread().id}")
            delay(1000)
        }
    }

runBlocking启动的协程任务会阻断当前线程,直到该协程执行结束。

2.launch

    fun launch() {
        var job: Job = GlobalScope.launch {
            repeat(5) {
                Log.i("minfo", "协程执行$it,当前线程id:${Thread.currentThread().id}")
                delay(1000)
            }
        }
    }

launch启动的协程不会阻断当前线程。

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}

launch() 是CoroutineScope的一个扩展函数,CoroutineScope简单来说就是协程的作用范围。CoroutineScope.launch返回类型为Job类型。

取消协程

GlobalScope.launch返回对象job可直接调用cancel取消协程。

 job.cancel()
协程下上文

上下文有一个重要的作用就是线程切换,Kotlin协程使用调度器来确定哪些线程用于协程执行,Kotlin提供了调度器给我们使用:
Dispatchers.Main:在主线程中运行协程
Dispatchers.IO:在线程池中执行协程
Dispatchers.Default:在线程池中执行协程
Dispatchers.Unconfined:在当前调用的线程中执行

协程体

协程体是一个用suspend关键字修饰的一个无参,无返回值的函数类型。被suspend修饰的函数称为挂起函数,与之对应的是关键字resume。

那我们写一个模拟切到子线程进行耗时操作:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //开启一个协程,切换到主线程
        GlobalScope.launch(Dispatchers.Main) {
            tvContent.text = loadData()
        }
    }

    /**
     * 模拟访问接口获取接口数据
     */
    suspend fun loadData(): String {
        var response = ""
        withContext(Dispatchers.IO) {
            //子线程中模拟耗时操作
            for (i in 0..10000000) {

            }
            response = "response"
        }

        return response
    }

}

loadData方法将协程挂起,协程中其后面的代码永远不会执行,只有等到loadData挂起结束恢复后才会执行。

Retrofit结合协程使用:

Retrofit从2.6.0开始已经支持协程了,如果在网络请求框架中,引入Rxjava仅仅用来与Retrofit结合使用,那就太没有必要了。我们可以用协程来代替Rxjava这部分的功能。

在ApiService类中声明一个请求函数 ,声明为挂起函数,类型不需要添加Call。

interface ApiService {

    @GET("v7/index/tab/discovery")
    suspend fun getFindData(): BaseResponse
}

返回数据实体类:

open class BaseResponse : Serializable {

    var count: Int = 0

    var total: Int = 0

    var nextPageUrl: String? = null

    var adExist: Boolean? = false
}

协程结合retrofit使用

    fun retrofitUse() {
        var retrofit = Retrofit.Builder()
                .baseUrl("http://baobab.kaiyanapp.com/api/")
                .addConverterFactory(GsonConverterFactory.create())
                .build()

        val apiService = retrofit.create(ApiService::class.java)

        GlobalScope.launch(Dispatchers.Main) {
            try { //try catch同于onFailure的回调
                tvContent.text = apiService.getFindData().toString()
            } catch (e: Exception) {
                tvContent.text = e.toString()
            }
        }
    }
参考

Kotlin 协程 看这一篇就够了
Kotlin协程

相关文章

网友评论

    本文标题:Kotlin协程使用

    本文链接:https://www.haomeiwen.com/subject/osdfpktx.html