Coroutine(协程)(四)和retrofit搭配使用

注意:Coroutine和retrofit的使用在retrofit2.6之前之后是有区别的

一、定义接口

/**
 * 可以从如下网址查找测试api
 * https://www.wanandroid.com/blog/show/2
 */
interface NewService {
    /**
     * 首页的 banner 的请求
     * 2.6.0以前不需要suspend,返回值是Deferred
     */
    @GET("/banner/json")
    suspend fun getBanner(): Response
}

二、创建retrofit

        val retrofit = Retrofit.Builder()
                .baseUrl("https://www.wanandroid.com")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(CoroutineCallAdapterFactory())//这里和普通retrofit用法有区别,注意一下
                .build()
        val service = retrofit.create(NewService::class.java)

另外把依赖贴出来

    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.1'
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
    implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.0'//LifecycleScope

三、Coroutine的使用

    val mainScope = MainScope()

    override fun onDestroy() {
        super.onDestroy()
        mainScope.cancel()
    }

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

        val retrofit = Retrofit.Builder()
                .baseUrl("https://www.wanandroid.com")
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(CoroutineCallAdapterFactory())//这里和普通retrofit用法有区别,注意一下
                .build()
        val service = retrofit.create(NewService::class.java)

        mainScope.launch(/**MyDispatcher()*/) {
            // 2.6.0以前需要在最后调用await()函数。2.6.0以后就不需要了
            //retrofit运行getBanner的时候会自动在子线程,所以MyDispatcher可以不用
            val data = service.getBanner()
            withContext(mainScope.coroutineContext) {
                if (isFinishing) {

                }
            }
        }

    }

注意一下mainScope和MyDispatcher

mainScope是Coroutine默认的用来处理UI的scope,类似于我们常说的“主线程”。具体用法就是先new一个出来,然后在页面destroy的时候调用cancel来释放所有未完成的job

MyDispatcher是用来解决线程池共用的问题。如果要用到项目中去,那么必然会涉及到和原来的retrofit共用同一个线程池。Dispatchers.Default里面分为DefaultScheduler和CommonPool。我就仿照这两个自己写了一个MyDispatcher,里面包了一层Executors.newFixedThreadPool

    class MyDispatcher : CoroutineDispatcher() {
        private var pool = Executors.newFixedThreadPool(10)//这里可以考虑和以前老的retrofit共用同一个线程池
        override fun dispatch(context: CoroutineContext, block: Runnable) {
            try {
                pool.execute(block)//模仿CommonPool的实现方法
            } catch (e: Exception) {
            }
        }
    }

当然,如果不用MyDispatcher也可以用ioScope,这个是仿照mainScope来写的

    val ioScope = SupervisorJob() + Dispatchers.IO

四、比较与取舍

首先我们要明确,Coroutine本来是准备来取代Rxjava的。毕竟Rxjava有两个缺点,第一个学习成本很大,很多人学了两三年也仅仅只是会熟练运用而已(包括我。。。),一旦出了问题,很多时候就是无从下手(从学习成本角度来讲Coroutine简单多了)。第二个线程切换代价大。主要区别就是协程切换完全在用户空间进行,而线程切换需要在内核空间完成。用户空间相比内核空间CPU耗时更少(可以类比浅睡眠和深睡眠)。
具体可以看
为什么协程切换的代价比线程切换低?
破解 Kotlin 协程 番外篇(1) - 协程为什么被称为『轻量级线程』?

你可能感兴趣的:(Coroutine(协程)(四)和retrofit搭配使用)