日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

超简单-用协程简化你的网络请求吧,兼容你的老项目和旧的网络请求方式

發(fā)布時(shí)間:2025/3/21 编程问答 59 豆豆
生活随笔 收集整理的這篇文章主要介紹了 超简单-用协程简化你的网络请求吧,兼容你的老项目和旧的网络请求方式 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

在Kotlin協(xié)程(后簡稱協(xié)程)出來之后,顛覆了我們很多工具類的封裝方式,大大簡化了我們很多api的調(diào)用,并且使異步操作邏輯更清晰了

其中一個(gè)很標(biāo)志性的地方就屬網(wǎng)絡(luò)請求了,以前的網(wǎng)絡(luò)請求方式聲明很麻煩,請求和響應(yīng)也很麻煩,總結(jié)一句話就是啰嗦且易出錯(cuò)

ps:最終的使用方式示例:

使用網(wǎng)絡(luò)請求的進(jìn)化過程:

1.從一開始的HttpURLConnection的一把梭,直接一個(gè)請求寫一串代碼(代碼太多就不寫了)

2.到后續(xù)使用三方封裝的網(wǎng)絡(luò)框架,如XUtils,Volly,OkHttp等,這些雖然也簡化了操作,但也是很復(fù)雜,比如封裝了兩層的OkHttp可能還需要以下方式聲明和調(diào)用:

然后在一個(gè)或多個(gè)回調(diào)中處理返回的數(shù)據(jù)并判斷是否是請求成功,解析成響應(yīng)的數(shù)據(jù)并操作

3.后來Retrofit出現(xiàn),解救了苦于網(wǎng)絡(luò)請求太啰嗦的萬千開發(fā)們,其使用動(dòng)態(tài)代理加良好的封裝,使網(wǎng)絡(luò)請求聲明和請求都變得更簡單了

ps:Retrofit如何使用動(dòng)態(tài)代理參考:模仿Retrofit封裝一個(gè)使用更簡單的網(wǎng)絡(luò)請求框架_lt的博客-CSDN博客_retrofit封裝網(wǎng)絡(luò)請求

pps:進(jìn)一步簡化Retrofit的聲明參考:更易于使用的Retrofit(不用寫注解)_lt的博客-CSDN博客

聲明如下(其會(huì)在調(diào)用的時(shí)候自動(dòng)解析成一個(gè)post請求的Call對象):

使用如下:

可以發(fā)現(xiàn)雖然聲明簡單了很多,但使用還是比較麻煩

這時(shí)候就輪到協(xié)程登場了

正文

如果是使用Retrofit配合協(xié)程簡化網(wǎng)絡(luò)請求參考我以前寫的文章第二條(封裝網(wǎng)絡(luò)請求):Kotlin協(xié)程在項(xiàng)目中的實(shí)際應(yīng)用_lt的博客-CSDN博客_kotlin協(xié)程使用

否則可以看下面的:

接下來就是重頭戲:用協(xié)程兼容你的老項(xiàng)目和舊的網(wǎng)絡(luò)請求方式,并且請求方式就像這張圖一樣

首先我們可以觀察一下我們的舊方式的請求,發(fā)現(xiàn)可能是有一個(gè)統(tǒng)一的回調(diào),將服務(wù)端返回的String返回來,可能類似情況1:

?也可能使用OkHttp,類似情況2:

也可能類似情況3:

?可以觀察到,他們都是基于回調(diào),而協(xié)程可以將回調(diào)轉(zhuǎn)成同步的掛起函數(shù),所以我們將第三種方式(其他情況也類似),改造代碼如下:

interface BaseHttp {//網(wǎng)絡(luò)請求成功后調(diào)用該方法fun onHttpSuccess(data: String?)//網(wǎng)絡(luò)請求失敗后調(diào)用該方法fun onHttpFailed(message: String?) }/*** creator: lt lt.dygzs@qq.com* effect : 使用協(xié)程封裝基于回調(diào)的網(wǎng)絡(luò)請求* warning:*/ abstract class CoroutineHttp<T : Any> : BaseHttp {private var continuation: CancellableContinuation<Result>? = null//協(xié)程對象,如果getX調(diào)用慢于回調(diào)用private var result: Result? = null//響應(yīng)結(jié)果,如果getX先與回調(diào)用//網(wǎng)絡(luò)請求成功后調(diào)用該方法 //2*********************************override fun onHttpSuccess(data: String?) {//保證線程安全handler.post {val continuation = continuationif (continuation == null) {result = Result(data, true)return@post}continuation.resume(Result(data, true))}}//網(wǎng)絡(luò)請求失敗后調(diào)用該方法override fun onHttpFailed(message: String?) {handler.post {val continuation = continuationif (continuation == null) {result = Result(message, false)return@post}continuation.resume(Result(message, false))}}/*** 檢查協(xié)程網(wǎng)絡(luò)請求的返回值和當(dāng)前狀態(tài)是否符合要求* 如果不符合要求,會(huì)回調(diào)失敗的接口,并返回null,不會(huì)取消當(dāng)前協(xié)程* [errorListener]msg:服務(wù)端返回的消息或異常信息,如果不傳使用默認(rèn)失敗策略(即彈toast)*/ //1*********************************suspend fun getOrNull(errorListener: (msg: String?) -> Unit = HttpErrorListener): T? {//保證線程安全val json = withContext(Dispatchers.Main) {val result = suspendCancellableCoroutine<Result> { continuation ->val result = resultif (result != null) { //4*********************************continuation.resume(result)return@suspendCancellableCoroutine}this@CoroutineHttp.continuation = continuation} //3*********************************return@withContext if (result.isSuccess) result.data else {errorListener(result.data)null}}return withContext(Dispatchers.Default) {Gson().fromJson(json,this@CoroutineHttp.getSuperClassTypes().first())}}/*** 檢查協(xié)程網(wǎng)絡(luò)請求的返回值和當(dāng)前狀態(tài)是否符合要求* 如果不符合要求,會(huì)回調(diào)失敗的接口,并取消當(dāng)前協(xié)程* [errorListener]msg:服務(wù)端返回的消息或異常信息,如果不傳使用默認(rèn)失敗策略(即彈toast)*/suspend fun get(errorListener: (String?) -> Unit = HttpErrorListener): T =getOrNull(errorListener) ?: cancelAndThrow()//獲取協(xié)程數(shù)據(jù),并自動(dòng)顯示和隱藏彈窗,并自動(dòng)轉(zhuǎn)換成響應(yīng)類型,如果請求失敗或轉(zhuǎn)換失敗則返回nullsuspend fun getOrNullWithDialog(errorListener: (String?) -> Unit = HttpErrorListener): T? {val baseActive = coroutineContext[CoroutineElementWithBaseActive]?.baseActivebaseActive?.showWaitDialog()try {return getOrNull(errorListener)} finally {baseActive?.dismissWaitDialog()}}// 獲取協(xié)程數(shù)據(jù),并自動(dòng)顯示和隱藏彈窗,并自動(dòng)轉(zhuǎn)換成響應(yīng)類型,如果請求失敗或轉(zhuǎn)換失敗則取消協(xié)程suspend fun getWithDialog(errorListener: (String?) -> Unit = HttpErrorListener): T =getOrNullWithDialog(errorListener) ?: cancelAndThrow()class Result(val data: String?, val isSuccess: Boolean)private object HttpErrorListener : (String?) -> Unit {override fun invoke(p1: String?) {p1.showToast()}}/*** 取消并拋出異常*/suspend fun cancelAndThrow(): Nothing = coroutineContext.job.cancelAndThrow()/*** 獲取super的泛型的type列表*/ fun Any.getSuperClassTypes(): Array<Type> =this::class.java.genericSuperclass.asT<ParameterizedType>().actualTypeArguments }private val handler = Handler(Looper.getMainLooper())

原理大致就是將協(xié)程內(nèi)部的回調(diào)給保存下來(掛起),然后在適當(dāng)?shù)臅r(shí)間調(diào)用協(xié)程的resume使協(xié)程恢復(fù)執(zhí)行

可以看代碼標(biāo)識1處,其他的getxxx方法都會(huì)走到這個(gè)getOrNull方法中,其先調(diào)用suspendCancellableCoroutine方法將協(xié)程掛起并拿到內(nèi)部的回調(diào)

然后再看代碼標(biāo)識2處,網(wǎng)絡(luò)請求回調(diào)成功后會(huì)走這個(gè)onHttpSuccess方法,然后我們判斷是否已經(jīng)掛起了協(xié)程(注冊了協(xié)程的回調(diào)):

? ? 1.如果掛起了,就調(diào)用resume恢復(fù)協(xié)程的運(yùn)行,此時(shí)代碼會(huì)執(zhí)行到標(biāo)識3處,且將result傳了過去,然后后續(xù)就執(zhí)行解析json并判斷是否成功等耦合項(xiàng)目的邏輯

? ? 2.如果沒有掛起,就將數(shù)據(jù)保存在類中,然后會(huì)在調(diào)用getxxx方法時(shí)檢測到有數(shù)據(jù)并直接恢復(fù)協(xié)程(標(biāo)識4處)

然后比如網(wǎng)絡(luò)請求這樣聲明:

最后我們就可以使用協(xié)程請求網(wǎng)絡(luò)了(紅框的位置相當(dāng)于getWithDialog方法的成功回調(diào)):

?也可以在方法后面?zhèn)魅牖卣{(diào)處理請求失敗的情況(紅框位置是成功的回調(diào),黃框位置是失敗的回調(diào)):

?使用協(xié)程和gson解析需要導(dǎo)入以下的依賴:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'implementation 'com.google.code.gson:gson:2.8.7'

擴(kuò)展

1.CoroutineHttp為什么要聲明為抽象類?

因?yàn)閖vm的泛型擦除,如果你不創(chuàng)建出新的Class,就無法獲取他設(shè)置的泛型的Type,而使用抽象類,你每new一個(gè)匿名內(nèi)部類都會(huì)創(chuàng)建出一個(gè)Class,所以可以通過反射獲取其聲明的泛型的Type

當(dāng)然open class也可以寫出匿名內(nèi)部類,但是沒有了硬性規(guī)定容易出現(xiàn)遺漏導(dǎo)致出現(xiàn)bug

2.mainScope是什么

mainScope是一個(gè)自定義的協(xié)程作用域(CoroutineScope),創(chuàng)建它可以參考這一篇Kotlin-如何創(chuàng)建一個(gè)好用的協(xié)程作用域_lt的博客-CSDN博客

一般在activity中需要在onCreate中創(chuàng)建,在onDestroy中調(diào)用cancel()來取消它所有啟動(dòng)的協(xié)程

如果在fragment中就在onCreate中創(chuàng)建,在onDestroyView中調(diào)用cancel()

如果有疑問可以評論區(qū)留言

end

《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結(jié)

以上是生活随笔為你收集整理的超简单-用协程简化你的网络请求吧,兼容你的老项目和旧的网络请求方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。