Android秀翻天的操作——使用協程進行網絡請求

一、前言

古往今來,時代順應潮流,潮流引領時代。

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 的協程還有諸多騷操作,各位道友自行挖掘,一定會挖到珍寶仙器。(這麼騷的操作,你不準備點個贊嗎?🤧)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章