0
点赞
收藏
分享

微信扫一扫

【思货】kotlin协程优雅的与Retrofit缠绵-正文,贼厉害

敬亭阁主 2022-03-11 阅读 83
面试

api.login(“1”, “1”).observe(this, Observer {string ->

})

以上就是最基础的使用方式,在项目中使用时候,通常会自定义Observer,用来将各种数据进行区分。

在上面调用的observe方法中,我们传递了一个this,这个this指的是声明周期,一般我们在AppCompatActivity中使用时,直接传递其本身就可以了。

下面简单跳转源码进行说明下。通过查看源码可以发现:

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer)

this本身是传递的LifecycleOwner

那么我们在一层层跳转AppCompatActivity,会发现AppCompatActivity是继承于SupportActivity的父类:

public class SupportActivity extends Activity implements LifecycleOwner, Component

其本身对LifecycleOwner接口进行了实现。也就是说,除非特殊要求,一般我们只需要传递其本身就可以了。LiveData会自动处理数据流的监听和解除绑定。

通常来说:在onCreate中对数据进行一次性的绑定,后面就不需要再次绑定了。

当生命周期走到onStartonResume的时候,LiveData会自动接收事件流;

当页面处于不活动的时候,将会暂停接收事件流,页面恢复时恢复数据接收。(例如A跳转到B,那么A将会暂停接收。当从B回到A以后,将恢复数据流接收)

当页面onDestroy时候,会自动删除观察者,从而中断事件流。

可以看出LiveData作为官方套件,使用简单,生命周期的响应也是很智能的,一般都不需要额外处理了。

(更高级的用法,可以参考官方Demo,可以对数据库缓存等待都进行一整套的响应式封装,非常nice。建议学习下官方的封装思想,就算不用,也是对自己大有裨益)

4. Kotlin协程

上面说了那么多,这里步入了正题。大家仔细观察下会发现,上面均是使用的Retrofitenqueue异步方法,再使用Callback进行的网络回调,就算是RxJava和Livedata的转换器,内部其实也是使用的Callback。在此之前,Retrofit的作者也写了一个协程的转换器,地址在这,但内部依然使用的是Callback,本质均为一样。(目前该库才被废弃,其实我也觉得这样使用协程就没意义了,Retrofit在最新的2.6.0版本,直接支持了kotlin协程的suspend挂起函数),

之前了解Retrofit的小伙伴应该知道,Retrofit是有同步和异步两种调用方式的。

void enqueue(Callback callback);

上面这就是异步调用方式,传入一个Callback,这也是我们最最最常用到的方式。

Response execute() throws IOException;

上面这种是同步调用方法,会阻塞线程,返回的直接就是网络数据Response,很少使用。

后来我就在思考,能不能结合kotlin的协程,抛弃Callback,直接使用Retrofit的同步方法,把异步当同步写,代码顺序书写,逻辑清晰,效率高,同步的写法就更加方便对象的管理。

说干就干。

首先写一个协程的扩展方法:

val api = ……
fun CoroutineScope.retrofit() {
this.launch(Dispatchers.Main) {
val work = async(Dispatchers.IO) {
try {
api.execute() // 调用同步方法
} catch (e: ConnectException) {
e.logE()
println(“网络连接出错”)
null
} catch (e: IOException) {
println(“未知网络错误”)
null
}
}
work.invokeOnCompletion { _ ->
// 协程关闭时,取消任务
if (work.isCancelled) {
api.cancel() // 调用 Retrofit 的 cancel 方法关闭网络
}
}
val response = work.await() // 等待io任务执行完毕返回数据后,再继续后面的代码

response?.let {

if (response.isSuccessful) {
println(response.body()) //网络请求成功,获取到的数据
} else {
// 处理 HTTP code
when (response.code()) {
401 -> {
}
500 -> {
println(“内部服务器错误”)
}
}
println(response.errorBody()) //网络请求失败,获取到的数据
}

}
}
}

上面就是核心代码,主要的意思都写了注释。整个工作流程是出于ui协程中,所以可以随意操作UI控件,接着在io线程中去同步调用网络请求,并且等待io线程的执行完毕,接着再拿到结果进行处理,整个流程都是基于同步代码的书写方式,一步一个流程,没有回掉而导致的代码割裂感。那么继续,我们想办法把获取的数据返回出去。

这里我们采用DSL方法,首先自定义一个类:

class RetrofitCoroutineDsl {
var api: (Call)? = null

internal var onSuccess: ((ResultType?) -> Unit)? = null
private set
internal var onComplete: (() -> Unit)? = null
private set
internal var onFailed: ((error: String?, code, Int) -> Unit)? = null
private set

var showFailedMsg = false

internal fun clean() {
onSuccess = null
onComplete = null
onFailed = null
}

fun onSuccess(block: (ResultType?) -> Unit) {
this.onSuccess = block
}

fun onComplete(block: () -> Unit) {
this.onComplete = block
}

fun onFailed(block: (error: String?, code, Int) -> Unit) {
this.onFailed = block
}

}

此类对外暴露了三个方法:onSuccessonCompleteonFailed,用于分类返回数据。

接着,我们对我们的核心代码进行改造,将方法进行传递:

fun CoroutineScope.retrofit(
dsl: RetrofitCoroutineDsl.() -> Unit //传递方法,需要哪个,传递哪个
) {
this.launch(Dispatchers.Main) {
val retrofitCoroutine = RetrofitCoroutineDsl()
retrofitCoroutine.dsl()
retrofitCoroutine.api?.let { it ->
val work = async(Dispatchers.IO) { // io线程执行
try {
it.execute()
} catch (e: ConnectException) {
e.logE()
retrofitCoroutine.onFailed?.invoke(“网络连接出错”, -100)
null
} catch (e: IOException) {
retrofitCoroutine.onFailed?.invoke(“未知网络错误”, -1)
null
}
}
work.invokeOnCompletion { _ ->
// 协程关闭时,取消任务
if (work.isCancelled) {
it.cancel()
retrofitCoroutine.clean()
}
}
val response = work.await()
retrofitCoroutine.onComplete?.invoke()
response?.let {
if (response.isSuccessful) {
retrofitCoroutine.onSuccess?.invoke(response.body())
} else {
// 处理 HTTP code
when (response.code()) {
401 -> {
}
500 -> {
}
}
retrofitCoroutine.onFailed?.invoke(response.errorBody(), response.code())
}
}
}
}
}

这里使用DSL传递方法,可以更具需要传递的,例如只需要onSuccess,那就只传递这一个方法,不必三个都传递,按需使用。

使用方式:

其他重要知识点

下面是有几位Android行业大佬对应上方技术点整理的一些进阶资料。有**【Android架构视频+BATJ面试专题PDF+核心笔记等资料+源码+思维导图】。希望能够帮助到大家提升技术。如果大家想要获取的话,可以私信我【666】免费获取哦~**

高级进阶篇——高级UI,自定义View(部分展示)

UI这块知识是现今使用者最多的。当年火爆一时的Android入门培训,学会这小块知识就能随便找到不错的工作了。不过很显然现在远远不够了,拒绝无休止的CV,亲自去项目实战,读源码,研究原理吧!

  • 面试题部分合集

(部分展示)**

UI这块知识是现今使用者最多的。当年火爆一时的Android入门培训,学会这小块知识就能随便找到不错的工作了。不过很显然现在远远不够了,拒绝无休止的CV,亲自去项目实战,读源码,研究原理吧!

[外链图片转存中…(img-Iq2JIyYl-1646482556082)]

  • 面试题部分合集
    [外链图片转存中…(img-cXgB6eqZ-1646482556082)]
举报

相关推荐

0 条评论