Android秀翻天的操作——使用协程进行网络请求

本文已独家授权 郭霖 ( guolin_blog) 公众号发布!

一、前言

古往今来,时代顺应潮流,潮流引领时代。

Android 网络界发展至今已经出现过无数风流框架,看先祖 HttpURLConnection 老矣,HttpClient 也早已隐退,而那 android-async-http 力不从心却也封刀,但江湖却还流传着它的故事,有那谷歌亲儿子 volley 独占中州,笑迎四面八方来客,OkHttp 不慌不急,稳占其余大洲,更有它那亲爹 Retrofit 默默支撑着它,使得各位风骚道友能够有安稳的栖身之地。

是年三月(瞎编的),异步界 RxJava “异军” 突起,揍扁太子 AsnyTask 逐渐统一异步界,成为异步界的霸主,RxJava 虽不闻不问网络界的是非,但是偶然的一次相遇,使得 RxJavaRetrofit 如胶似漆,殊不知,这是 Retrofit 的计谋,想要借助 RxJava 这个工具人,壮大自己的实力,进一步统一网络界!

又不知过了多少年岁,天地宇宙各界各地突然出现崩塌迹象,无端出现莫名其妙的裂缝!裂缝每时每刻都在将每片区域空气中的 Java 吸走!十分霸道!各界每位风骚道友都人心惶惶,没有了 Java ,道友们就不能够呼吸,正当道友们岌岌可危之时,那些裂缝竟然反吐一种令人心旷神怡的气体——Kotlin,道友们呼吸到 Kotlin 之后,神宁瞬间安静,甚至表情中都泛有一丝春光!大家逐渐都爱上了这个新的气体。他们还发现,在练功时如果使用 Kotlin, 每个大周天提炼的灵力竟然比使用 Java 多出一倍有余!

不仅仅是各位道友注意到了 Kotlin 的神奇之处,想那妖艳贱货 Retrofit 也早就领会 Kotlin 之妙用,终有一天,Retrofit 不满 RxJava 花心浪荡,摔杯举剑,只见那秀剑飞起,在手中720度托马斯回旋,“撕拉”一声,割袍断义,与 RxJava 分道扬镳……

二、Kotlin协程

在太岁一年三月……啊呸,在 Kotlin 1.3版本中 协程 逐步稳定,我们可以放心大胆的使用,关于 协程 的概念和使用详解,我无法做出太多介绍,这东西太玄学了,因为没有开放源码,江湖上没有几个道友能够彻底理解,或许也只有几位不出世的高人才能够熟知吧……

这里做个简单的介绍(点击获取更多详情😀):

协程可看作是一个轻量级的线程,协程必须依附在某个线程,类似于守护线程,当协程依附的线程被干掉(或者正常结束),那么这个协程也会挂掉。

三、协程和Retrofit

关于 Retrofit 如何使用,道友们肯定很是熟知😍:

interface ApiService{
    @GET("url/request")
    fun doRequest():Call<ResponseBody>
}

fun main() {
    Retrofit.Builder().build()	//这 里 只 是 意 思 意 思 一 下 ! ! !
    .create(ApiService::class.java)
    .doRequest()
    .enqueue(object : Callback<ResponseBody> {
        override fun onFailure(call: Call<ResponseBody>, t: Throwable) { }
        override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) { }
    })
}

2019年2月16号 ,那个地球上最牛逼的道友——JakeWharton 对 Retrofit 提交了一个重要的代码:
图片
支持了协程!当我们 点进去 的时候,可以看看关键的文件和代码。一个名叫 KotlinExtensions.kt 的文件增加了 3个 Kotlin 扩展方法。

这 3个方法就是用来配合协程一起来搞骚操作的。如果道友们因为种种原因,不能更新 Retrofit 比较新的版本,那么可以尝试自己去复制这几个方法到自己的扩展函数中。

四、预备工作

建议先看看 第五小节,等你觉得爽了再来看看这个如何实现。

1、准备好Retrofit

如上一小节所述,如果你没法更新 Retrofit ,那么你就在自己的扩展文件中添加一个扩展方法即可,这 3个方法没必要都写上去,他们的本质都是一样的,所以我们只要挑选一个 基本款 车型即可,然后随你怎么加装配件都行:

/**
 * 某 KtExtension.kt 文件
 */
suspend fun <T : Any> Call<T>.await(): Response<T> {
  return suspendCancellableCoroutine { continuation ->
  	//车况异常处理装置
    continuation.invokeOnCancellation {
      cancel()
    }
    enqueue(object : Callback<T> {
      override fun onResponse(call: Call<T>, response: Response<T>) {
      	//1.基本款装置
        continuation.resume(response)
        
        //2.加装改款胎压检测装置 <需替换基本款装置>
        if (response.isSuccessful) {
            continuation.resume(response.body())
        } else {
            continuation.resumeWithException(HttpException(response))
        }
      }

      override fun onFailure(call: Call<T>, t: Throwable) {
      	//道路异常处理装置
        continuation.resumeWithException(t)
      }
    })
  }
}
2、准备好协程
  1. 我们先导入 Android 的协程扩展
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.5'

这样我们就能够轻松拿到主线程的协程上下文环境。

  1. 编写全局(或者局部,随你心情定)协程代码块方法

/** 
 * 某 KtExtension.kt 文件
 * 默认主线程的协程
 */
fun launch(block: suspend (CoroutineScope) -> Unit,
 		   error: ((e: Exception) -> Unit)? = null,
  	   	   context: CoroutineContext = Dispatchers.Main): Job {
    return GlobalScope.launch(context + CoroutineExceptionHandler { _, e ->
        Log.e("==>coroutineException", e.message)	//1
    }) {
        try {
            block(this)
        } catch (e: Exception) {		//2
            Log.e("==>coroutineError", e.message)
            if (error != null) {
                error(e)
            }
        }
    }
}

注意上面有两个异常捕获:1. 捕获整个协程的异常;2.捕获协程代码块执行的异常。为了保证程序的稳定,两个都必须要有。

五、使用

  1. 还是先定义请求接口
interface LoginApi {

    /**
     * 获取登录二维码
     */
    @GET("/xxx/xxx/xxx")
    fun getLoginQRBitmap(): Call<BaseResponse<String?>>
}
  1. 创建协程作用域

因为是全局方法,所以在哪里我们都能够调用

launch({
	//MainNet.server()是封装了Retrofit的过程,此过程就不展示了
    val bitmapEntity = MainNet.server(LoginApi::class.java).getLoginQRBitmap().await()   
   	println("二维码地址为:${bitmapEntity.data}")
   	//加载二维码,可以进行更新 UI 的操作
   	initBitmap(bitmapEntity.data)
    }, {
        //TODO 网络请求异常处理
})
  1. 控制中断协程

launch 这个方法会返回一个 Job,这个 Job 就相当于 RxJavaDisposable,可以调用其方法进行中断协程:

val job = launch({
	... ...
})
//中断协程
job.cancel()
  1. 简单说明

因为是依附在主线程的协程,所以你 完全可以launch 的作用域中更新UI,又因为是协程,所以网络请求的这个过程中你完全不必当心会阻塞 UI线程

六、小结

Kotlin 的协程还有诸多骚操作,各位道友自行挖掘,一定会挖到珍宝仙器。(这么骚的操作,你不准备点个赞吗?🤧)

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值