X

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

本文为网络转载文章。文章内观点不代表本博客立场。本转载仅用于技术学习与交流。

catzifeng博客地址:

https://blog.csdn.net/catzifeng

/   前言   /

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

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

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

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

/   Kotlin协程   /

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

协程官方文档:

https://www.kotlincn.net/docs/reference/coroutines/coroutines-guide.html

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

/   协程和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比较新的版本,那么可以尝试自己去复制这几个方法到自己的扩展函数中。

GitHub地址:

https://github.com/square/retrofit/commit/b761518aa174c7b0512b73f2fe70e2e908f24081#diff-afbee4f0294010620954bfa945075192

/   预备工作   /

准备好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)
      }
    })
  }
}

准备好协程

我们先导入Android的协程扩展:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.5'

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

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

/** 
 * 某 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.捕获协程代码块执行的异常。为了保证程序的稳定,两个都必须要有。

/   使用   /

先定义请求接口

interface LoginApi {

    /**
     * 获取登录二维码
     */    @GET("/xxx/xxx/xxx")
    fun getLoginQRBitmap(): Call<BaseResponse<String?>>
}

创建协程作用域

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

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

控制中断协程

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

val job = launch({
    ... ...
})
//中断协程
job.cancel()

简单说明

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

/   总结   /

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

关注我获取更多知识或者投稿

本网站文章均为原创内容,并可随意转载,但请标明本文链接
如有任何疑问可在文章底部留言。为了防止恶意评论,本博客现已开启留言审核功能。但是博主会在后台第一时间看到您的留言,并会在第一时间对您的留言进行回复!欢迎交流!
本文链接: http://leetcode.jp/android编程-android秀翻天的操作-使用协程进行网络请求/
Categories: Android
admin: