Android开发中的Kotlin Coroutine VS RxJava

前言

首先,我是个Kotlin的重度使用者。我用Kotlin写过后台应用,写过前端,写过近10个Android项目。

我个人觉得,Kotlin充满了现代化的软件开发所需的语言特色,在我用过的所有语言中(ES6,Python,Go,Java)是最舒服最自然的;JetBrain做了多年IDE,最懂开发者的尿性。如果你会Java,几乎没有学习成本。除了其他优秀的语法外,我也格外喜欢Coroutine,下面就来吹一波。

先吹一波

Coroutine,也叫协程,或者微线程(或者随便你怎么叫它);它是可暂停可恢复的比线程更小的任务单元。目前我所用到的支持协程序的语言有NodeJS,Go,Python;Java并不支持。从原理上看,它们的核心实现原理大都是OS Thread Pool + 状态机,就是靠系统线程池来调度,靠状态机来控制状态。只不过有些是语言天然就支持的,比如Go;而Kotlin是用编译技术来实现的。

不管如何实现,它们一般有这样2个好处:

  1. 更低资源消耗和更好的调度性能
  2. 异步代码变同步

至于第一点在Web应用上很实用,因为Web大多是IO密集,它在低配置的机器上可以带来更高的并发,资源消耗还少。但是在Andorid上然并卵,就算是多线程下载的场景,一般并发任务也就5个左右,根本体现不出它的作用。

第二点在Android上就很实用了,我们经常会遇到先执行一段耗时操作,在执行一段后续逻辑的场景。不然Andorid也不会搞出AsyncTask,IntentService,HandlerThread了。它可以完全消除我们的callback。

场景

先看一个真实的发布动态场景。动态中包含文字,用户拍摄或选择的9张图片。整个动态的发布流程是这样:

  1. 先异步对9张图片进行压缩
  2. 然后异步将9张图片上传到Server,拿到9个图片Id
  3. 将文字和图片Id一块上传

第1步,第2步和第3步本身都是需要异步,但1,2,3步之间又是同步顺序执行的关系。

Java中可以用FutureTask实现。

用RxJava来做大概是大量的Callback流配合map操作符来完成,代码虽然比FetureTask好很多,但是并不美观。

用Kotlin Coroutine来做就是:

GlobalScope.launch {
    // 其他参数
    val params = hashMapOf(
            "content" to content,
            "longitude" to longitude,
            "latitude" to latitude,
            "title" to title
    )
    
    //1. 构建压缩图片的task
    val compressedTasks = paths.map { compressImage(it) } // paths是用户的图片地址集合
    //2. 构建上传图片的task,上传任务就是http请求
    val uploadTasks = compressedTasks.map { uploadImage(it.await()) } //压缩任务并发执行
    //3. 执行上传图片task拿到结果
    val imageIds = uploadTasks.map { it.await()!!.data.id } // 上传图片任务并发执行
    params["images"] = imageIds.toJson()

    val result = "$BASEURL/weibo/create".http(this)
            .headers(...)
            .params(params)
            .post<HttpResult<Dynamic>>().await()
            
    // 更新LiveData        
    weiboCreateData.postValue(result)
}
复制代码

几个构建task的代码在这里:

/**
 * 构建压缩任务
 */
fun compressImage(path: String): Deferred<File>{
    val deferred = CompletableDeferred<File>()
    // 这里是使用Luban库来压缩图片,具体逻辑可以忽略
    deferred.complete(Luban.with(App.context)
            .load(path)
            .ignoreBy(100)
            .get()[0])
    return deferred
}

/**
 * 构建上传图片的任务
 */
fun uploadImage(file: File): Deferred<HttpResult<List<UploadData>>?> {
    return "$BASEURL/weibo/upload".http(this)
            .headers(createCommonHeaders(null))
            .params("file" to file)
            .post<HttpResult<List<UploadData>>>()
}
复制代码

可以看到这种复杂逻辑下,全部代码也就30行左右,并且没有一个Callback,是不是比RxJava好。

上面的网络请求是来自于我的一个库:github.com/li-xiaojun/…

异步逻辑之后通知UI,我建议用LiveData,省去很多界面销毁的判断,而且监听可以自动解除注册,RxJava还要手动dispose。

如果你就想在UI中执行一段异步逻辑然后回到UI线程更新UI,那可以用anko库的封装。

最后

其实,我并不用RxJava,从看到大量的Callback时就放弃了。

我对RxJava并没有深入了解,对于上面的场景,如果RxJava能做的更好,烦请指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值