范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

KotlinCoroutine在Android中的使用和封装

  kotlin出来很多年,并被google被赋予Android首选开发语言的地位,还是有必要研究一下的,基础语法不再复述了,只简单聊聊kotlin中的核心内容之一:协程 Coroutine。
  相关概念和API可以直接进入[官网](https://kotlinlang.org/)查询,
  不过不推荐kotlin中文网,文章翻译的略显生硬,看了更容易迷惑。
  本文不讲基础(基础我也不怎么清楚…),适合喜欢拿来主义的同学
  协程作为轻量级的线程,是建立在线程之上的调度,比线程节省资源但不意味着不消耗资源,在Android这种系统资源相对珍贵的环境中,当异步繁琐的调用或者切换线程,如何及时的回收也是必要的工作。
  ### 一、添加依赖配置
  coroutine 是在kotlin 1.3中发布的1.0正式版,所以建议优先使用这个版本。
  项目根目录中gradle配置:buildscript {      ext.kotlin_version = "1.3.0"      repositories {          google()          mavenCentral()          jcenter()                }      dependencies {          classpath "com.android.tools.build:gradle:3.2.0"          classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"      }  }
  主module中gradle配置apply plugin: "kotlin-android"  apply plugin: "kotlin-android-extensions"  dependencies {      implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"      implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1"      implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1"  }  // 实验性开启协程的配置,目前版本中已经不需要了  kotlin{                   experimental{          coroutines "enable"      }  }
  假如你的其他module也使用kt代码,也需要添加上述依赖,不然有可能会出现找不到class或符号相关编译错误
  二、替换RxJava和升级Retrofit
  一般项目中会引用retrofit + RxJava的组合进行网络请求,或者你单独封装了一层RxJava来进行异步操作、切换线程来处理你的业务
  RxJava虽然操作符众多(得有100个以上了吧),上手不易,但着实好用,一条链走下来搞定你的全部业务,如果有网络请求配合上retrofit这种支持Rx的库,不要太给力。
  不过函数式开发有个通病,这条链子上会创建大量对象,回收内存抖动你不得不考虑,虽然使用了线程池,可开销不容小觑。
  RxJava 虽然可以链式调用,但终究还是基于回调形式,而协程完全做到了同步方式写异步代码。
  看下以前Retrofit的写法(简易)object RetrofitHelper: Interceptor {      init {          initOkHttpClient();      }      private var mOkHttpClient: OkHttpClient? = null      private val BASE_GANK_URL = "http://gank.io/api/"      fun getRetroFitBuilder(url :String) : Retrofit {          return Retrofit.Builder()                  .baseUrl(url)                  .client(mOkHttpClient)                  .addCallAdapterFactory(RxJavaCallAdapterFactory.create())                  .addConverterFactory(GsonConverterFactory.create())                  .build()      }      fun getGankMeiziApi(): GankMeiziAPI {          return getRetroFitBuilder(BASE_GANK_URL).create(GankMeiziAPI::class.java)      }  interface GankMeiziAPI {      @GET("data/福利/{number}/{page}")      abstract fun getGankMeizi(@Path("number") number: Int, @Path("page") page: Int): Observable  }  class GankMeiziPresenter : BaseMvpPresenter() {      fun getGankList(context: RxAppCompatActivity, pageNum: Int , page :Int){          RetrofitHelper.getGankMeiziApi()                  .getGankMeizi(pageNum, page)                  .subscribeOn(Schedulers.io())                  .compose(context.bindUntilEvent(ActivityEvent.DESTROY))                  .filter({ gankMeiziResult -> !gankMeiziResult.error })                  .map({ gankMeiziResult -> gankMeiziResult.results })                  .observeOn(AndroidSchedulers.mainThread())                  .subscribe({ gankMeiziInfos ->                      mvpView?.showSuccess(gankMeiziInfos)                  }, { throwable ->                      mvpView?.showError()                  })      }  }
  RxJava 的调用链上使用RxLife来绑定生命周期(或者使用Uber的autodispose),很常见的代码。
  对于RxJava你还有可能会封装一个小工具(主要是为了生命周期和回收问题)public class RxImpl {      public static  void exeOnLife(final AppCompatActivity mActivity , Observable> observable, final Accept acceptFun){          if (mActivity == null || ActivityHelper.activityIsDead(mActivity) || observable == null) return;          observable.as(AutoDispose.>autoDisposable(AndroidLifecycleScopeProvider.from(mActivity, Lifecycle.Event.ON_DESTROY)))                  .subscribe(new Consumer>() {                      @Override                      public void accept(RespBody respBody) throws Exception {                          if (acceptFun == null) return;                          acceptFun.accept(respBody);                      }                  });      }      public interface Accept  {          void accept(RespBody respBody);      }  }
  现在呢,想用协程怎么办,假设你现在已经知道了如何启动一个协程GlobalScope.launch { }            GlobalScope.async {}
  也知道了launch 和 async的区别(返回值不同),也知道了需要一个返回值和多个返回值的选择(async 和 reduce),那在Android中如何使用呢
  三、封装
  协程Job具有层级关系,父协程控制子协程的运行,取消父协程的运行,也就相当于关闭了所有你开在父协程里的全部任务,所以在基类中你需要声明一个全局的协程上下文,保证你开启的协程都处于这个context环境中,在onDestroy下取消全局context,就达到了你的目的abstract class AbstractFragment : RxFragment() , CoroutineScope by MainScope() {      override fun onDestroy() {          super.onDestroy()          cancel()      }  }
  你可以像封装RxJava一样,封装一个工具来使用协程,同时遵循一些原则:
  #### 1 调度器
  你开启的协程需要有调度器,就像RxJava自由切换线程一样,但主线程调度器最好指定Main来避免不必要的麻烦。
  举个例子,你使用RxJava+autodipose来绑定 生命周期,但你在子线程用RxJava又开启了一个新线程,调度回UI线程刷新view的时候会发生崩溃
  #### 2 父协程和子协程有强烈的层级关系
  cancel一个Job 会抛出 CancellationException ,但这个异常不需要开发人员管理,但如果协程内部发生了非 CancellationException ,则会使用这个异常来取消父Coroutine。为了保证稳定的Coroutine层级关系,这种行为不能被修改。 然后当所有的子Coroutine都终止后,父Coroutine会收到原来抛出的异常信息。
  下边是个协程的简易封装案例fun  executeRequest(context : CoroutineContext, request: suspend () -> T?, onSuccess: (T) -> Unit = {}, onFail: (Throwable) -> Unit = {}): Job {      return CoroutineScope(Dispatchers.Main).launch(context) {          try {              val res: T? = withContext(Dispatchers.IO) { request() }              res?.let {                  onSuccess(it)              }          } catch (e: Exception) {              e.printStackTrace()              onFail(e)          }      }  }
  context 视业务情况而定是否传入
  然后在你的act或Fragment中直接调用class MyFragment : BaseFragment {            onAcitvityCreate(){          executeRequest(              context,                  request = {                      // 异步任务                  },                  onSuccess = {                                       },                  onFail = {                                        }          )      }  }
  对于Retrofit修改更为简单,2.6版本已经支持了协程,网上有很多介绍interface GankMeiziAPI {      @GET("data/福利/{number}/{page}")      suspend fun getGankMeizi(@Path("number") number: Int, @Path("page") page: Int): GankMeiziResult  }
  将Observable返回值修改为你需要的bean, 加上suspend标记即可,
  下边是示例代码:return executeRequest(                 context,                  request = {                      RetrofitHelper.getGankMeiziApi().getGankMeizi(pageNum, page)                  },                  onSuccess = {                      mvpView?.showSuccess(it.results)                  },                  onFail = {                      mvpView?.showError()                  }          )
  ### 四、混淆
  网上的帖子大多以demo的思路来写,商用肯定要混淆了,不添加proguard你混淆后就死翘翘了,所以直接贴上来
  coroutine的配置-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}  -keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}  -keepnames class kotlinx.coroutines.android.AndroidExceptionPreHandler {}  -keepnames class kotlinx.coroutines.android.AndroidDispatcherFactory {}  -keepclassmembernames class kotlinx.** {      volatile ;  }
  假如release打包后你的Retrofit 请求结果发生了npe,检查下你的bean是否添加了不混淆配置
  ### 其他
  研究协程没多久,有错误或建议欢迎指出,共同交流
  另外推荐云在千峰的[博客](http://blog.chengyunfeng.com/?p=1088) ,是我目前看过的最友好的coroutine系列文章

长视频裁员潮要来了?据新浪报道,爱奇艺正在进行历史最大一次裁员,七千多员工预计裁掉2040。长视频行业亏掉上千亿后,爱奇艺终于坚持不下去,打响裁员第一枪,后面优酷腾讯的日子大概率也不会好过。和你们闲扯法媒67辆自动驾驶出租车在北京商业运营来源环球时报法国欧洲新闻电视台网站11月30日文章,原题一个由67辆无人驾驶的机器人出租车组成的车队开始在北京搭载付费乘客它看起来像一辆普通小汽车,但停靠在人行道旁的这种白色出租车各位买过二手手机没?是一种什么样的体验?感谢您的阅读!我的第1款安卓手机就是二手手机,我的第1款还是手机的名字叫做摩托罗拉MB200。这是我的第1款iPhone手机,当时使用的具体情况,其实是因为想要体验一下安卓系统,同小米12尝鲜!MIUI13稳定版准备就绪今天,开发者KacperSkrzypek在社交平台上爆料,MIUI13稳定版准备就绪(版本号为V13。0。1。0。SLBCNXM),这意味着全新一代MIUI13将有望与小米12同台曝小米12首批备货充足摩托罗拉抢骁龙8Gen1首发12月1日消息,在今天一早备受瞩目的高通发布会上,新一代旗舰芯片骁龙8Gen1终于揭开神秘面纱,这也是骁龙系更名后的第一代产品,同时意味着骁龙8Gen1将成为全新一代旗舰移动平台。网易云音乐港股上市破发丁磊好好吃顿饭然后忘掉今天雷递网乐天12月2日报道网易云音乐今日在港交所上市,发行价205港元,募资31。24亿港元。以发行价计算,网易云音乐市值为425亿港元。网易云音乐此次开盘价为205港元,与发行价持雷军霸气重申小米12全球首发骁龙8Gen1雷军表示,没有足够的实力,就很难把新平台的首发做好。比如需要关键器件的重新导入,需要全部硬件模块的全链路验证。内存不适配,要向内存厂商输出调试指引屏幕不兼容,就要重新开模定制显示芯定了!小米12将全球首发全新一代骁龙8移动平台,网友早猜到了随着全新一代骁龙8移动平台在骁龙技术峰会正式亮相,全球首发该芯片的手机厂家也终于揭晓,不出大家所料依旧是小米,12月1日小米官方公开宣布,将会在数字系列小米12上,搭载高通最新旗舰为什么年轻人都舍不得花钱吃好的,却舍得花钱买贵的衣服和手机?一个贵的手机可以用23年,贵的好的衣服可以穿两年左右!不舍得花钱吃的好吃的,因为觉得浪费,觉得自己不配!这年头你不可能穿的破破烂烂去工作,去谈合作跑业务吧!不过说实在的,我现在已经司马斗联想事件,联想似乎没有什么动作?他们在等什么?联想必须要有动作,昨天的新闻联播报导了国务院工作会议精神,明确严禁大企业利用其优势地位拖欠中小企业货款,长期拖欠的将予以严查。联想至少要把这事办了。联想的问题,不是一句话能说清楚,你有哪些意境壁纸?有意境,欣赏看。推荐两款款好看的壁纸给您,喜欢您喜欢!谢谢邀请,看看这些壁纸吧!更多壁纸在我的文章里,去看看吧!全面屏手机壁纸,19。59剪裁。电脑带鱼屏219壁纸。需要原图及更多
千里寻花香,顺联动力资本路演走进贵阳首先分享一个冷知识,只有贵州省,没有贵州市。苏州徐州广州杭州兰州贵州,是中国唯一一个带州字的省级行政单位。贵州省会是贵阳,其实往前追溯到宋元明三代,贵阳这座城市也被叫贵州叫了600拼购类社交电商,从哪里来?到哪里去?拼购类社交电商是建立在熟人社交的强关系链基础之上,通过价格优惠的方式引导消费者进行自主传播购买的分享型电商模式对于拼购类社交电商平台来说,在转型升级的过程中如何平衡消费者商家和平台深入华南腹地,顺联动力资本路演走进石都柳州说起柳州,首先排除风靡全国吃货的螺蛳粉,不然本场路演可能要增加美食鉴赏环节了。柳州以奇石闻名天下,被誉为中华石都壮族的歌侗族的楼苗族的舞瑶族的节,堪称柳州民族风情的四绝。以柳州为圆解决Win10Ping不通系统环境操作系统名称MicrosoftWindows10教育版版本10。0。18363内部版本18363起因今天在win10搭建FTP服务器的时候遇到了,内网的一台电脑ping不同将Kotlin添加到现有应用转载Fromhttpsdeveloper。android。google。cnkotlinaddkotlinAndroidStudio提供全面的Kotlin支持,让您能够将KotliAndroidStudio自动导包开发环境操作系统版本AndroidStudio版本设置打开Preferences,找到AutoImport,如下图勾选Addunambiguousimportsonthefly前面AndroidStudioGradle同步被中断的问题Failedtoopenzipfile。Gradlesdependencycachemaybecorrupt(thissometimesoccursafteranetworkcon混合开发JSDate在IOS端出现NaN问题起因在开发流程表单的时候,IOS同时跑过来问我,为什么选择时间后会变成NaN。在安卓端是正常显示的,网上查阅了一下,原来是IOS系统不支持YYYYmmdd这样格式的时间。。解决原来ITerm3快捷连接SSH普通操作sshp22192。168。1。1执行完上面输入密码就可以在终端操作服务器了快捷连接准备启动连接的脚本,然后保存在一个位置,例如UsersbeiniDocumentsserAssvn报E170013开发环境系统masOSBigSur版本11。2。2IdeaAndroidStudio版本4。1。2起因用SnailSVN下载了公司svn服务器代码,然后导入AndroidstudiWin10开启FTP服务系统环境操作系统名称MicrosoftWindows10教育版版本10。0。18363内部版本18363打开启用或关闭Windwos功能winR,输入control,打开控制面板然