前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Coroutine(协程)(四)和retrofit搭配使用

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

作者头像
提莫队长
发布2021-03-09 12:01:38
2.2K0
发布2021-03-09 12:01:38
举报
文章被收录于专栏:刘晓杰刘晓杰

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

一、定义接口

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

二、创建retrofit

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

另外把依赖贴出来

代码语言:javascript
复制
    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的使用

代码语言:javascript
复制
    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

代码语言:javascript
复制
    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来写的

代码语言:javascript
复制
    val ioScope = SupervisorJob() + Dispatchers.IO

四、比较与取舍

首先我们要明确,Coroutine本来是准备来取代Rxjava的。毕竟Rxjava有两个缺点,第一个学习成本很大,很多人学了两三年也仅仅只是会熟练运用而已(包括我。。。),一旦出了问题,很多时候就是无从下手(从学习成本角度来讲Coroutine简单多了)。第二个线程切换代价大。主要区别如下 (1)协程切换完全在用户空间进行,线程切换涉及特权模式切换,需要在内核空间完成; (2)协程切换相比线程切换做的事情更少。 具体可以看 为什么协程切换的代价比线程切换低? 现在的问题就出在这里,retrofit内部会自动去异步加载的,相当于又是开了一个线程。最终还是会回到线程切换,何必呢?个人觉得,协程更适合于那种不需要开子线程,同时又相当耗时的操作,比如循环遍历,文件操作,频繁的IO操作。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、定义接口
  • 二、创建retrofit
  • 三、Coroutine的使用
  • 四、比较与取舍
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档