国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

將kotlin協(xié)程用于網(wǎng)絡請求---完整實例,看這一篇就夠了

這篇具有很好參考價值的文章主要介紹了將kotlin協(xié)程用于網(wǎng)絡請求---完整實例,看這一篇就夠了。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前言:關(guān)于kotlin協(xié)程的介紹網(wǎng)上一大堆,用于網(wǎng)絡請求的介紹也是一大堆,此文章不講解各種原理,只講實例使用,只要你有kotlin基礎保證能看懂,看完就可以實際將kotlin協(xié)程應用于網(wǎng)絡請求,從此廢棄掉回調(diào)地獄,讓你的app飛起來吧

本文的網(wǎng)絡請求使用了Retrofit2 + okhttp,因為使用的是協(xié)程,就再也不需要回調(diào)地獄了,所以拋棄了Rxjava

1.先集成相關(guān)sdk

在app模塊目錄build.gradle中添加

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

..........
dependencies {
    implementation 'androidx.core:core-ktx:1.1.0-alpha04'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0-beta01'
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.0.0'
    implementation 'com.google.code.gson:gson:2.6.2'//解析接口返回的數(shù)據(jù)我用到了這個,如果你是用fastjson的話,可以忽略掉這個,繼續(xù)用fastjson就行了
    implementation 'com.squareup.retrofit2:retrofit:2.9.0' //這個版本很重要,必須要大于2.6.0,如果你的項目是低于2.6.0的話,更新一下版本,否則實際運行時會出現(xiàn)錯誤
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2"
}

2.創(chuàng)建Retrofit公共請求類

通常我們同一個項目,和服務器后端應該存在一些固定約束,比如接口返回的固定字段,會有code、message、data這些,那么發(fā)送給接口的請求,也應該有一些固定約束,比如固定的header等,所以就需要將網(wǎng)絡請求進行一層封裝

class RetrofitClient {
    //實際項目應用中,應該存在至少dev環(huán)境和idc線上環(huán)境,筆者這里還有test環(huán)境,如果你的項目沒有這些環(huán)境,那么可以直接return 唯一的地址,甚至這個方法都可以不需要,直接使用唯一的環(huán)境即可
    fun getCoroutineServiceApi():ServiceApi{
        if(HttpApi.baseIp == "xxx" || HttpApi.baseIp == "xxx"){
            return coroutineServiceApiDev
        }else{
            return coroutineServiceApiOnLine
        }
    }

    private val coroutineServiceApiDev: ServiceApi by lazy { //不清楚by lazy的自行去百度,這是委托模式,可以延遲加載,并且只在首次訪問時計算值
        val retrofitClient = Retrofit.Builder()
            .baseUrl(HttpApi.baseIp)
            .client(OkHttpClient.Builder()
                .addInterceptor(HttpLoggingInterceptor(HttpLoggingInterceptor.Logger { message ->
                    Log.i(TAG, message)
                }).setLevel(HttpLoggingInterceptor.Level.BODY)
                ).addInterceptor(Interceptor { chain ->
                    //這里就可以添加一些通用請求頭了
                    val request: Request = chain.request()
                        .newBuilder()
                        .addHeader("Content-Type", "application/json")
                        .addHeader("version", MyApplication.getInstances().getVersion())
                        .addHeader("deviceId", MyApplication.getInstances().getDeviceid())
                        .addHeader("osType", MyApplication.osType)
                        .addHeader("token",  token)
.addHeader("channelCode",MyApplication.getInstances().getChannelNo()+MyApplication.getInstances().getHumeChannel())
.addHeader("androidId",MyApplication.getInstances().getAndroidid())
                        .addHeader("ua",URLEncoder.encode(MyApplication.mUa,"UTF-8"))
                        .addHeader("oaid",MyApplication.getInstances().getOaid())
                        .addHeader("imei",MyApplication.getInstances().getIMEI())
                        .addHeader("uuid",MyApplication.getInstances().getuniqueId())
                        .addHeader("vendor",Build.MANUFACTURER)
                        .build()
                    KLogger.e("xiaolitest","當前uuid:"+MyApplication.getInstances().getuniqueId())
                    Log.e("xiaolitest","當前渠道:"+MyApplication.getInstances().getChannelNo())
                    chain.proceed(request)
                }).build())
            .addConverterFactory(DsGsonConverterFactory.create())//這里我是把接口返回的值序列化,就像上面說的,同一個項目,后臺和客戶端的數(shù)據(jù)返回應該有一些固定約束
            .build()
        retrofitClient.create(ServiceApi::class.java)
    }
    //coroutineServiceApiOnLine我就不貼了,寫法完全一樣,只是baseUrl不一樣而已,一個測試環(huán)境的,一個線上環(huán)境的
}

3.創(chuàng)建ServiceApi

上文中創(chuàng)建了Retrofit的屬性委托,返回的對象都是ServiceApi,那么就需要寫這個ServiceApi了

interface ServiceApi {
 @POST("card-user/xxx") //這個不用描述吧?懂retrofit的都知道,代表的是請求方式以及請求地址
 suspend fun getUserGotoTest():BaseResult<UserJumpConfigBean> //注意到開頭的suspend關(guān)鍵字了嗎?它很重要,因為協(xié)程體調(diào)用外部的方法,它必須是suspend的,否則會報錯
}


//貼一下BaseResult代碼,大部分的約束也應該如此
data class BaseResult <T>(
    val code :String,
    val success:Boolean,
    val message:String,
    val time:String,
    val data: T

)

4.創(chuàng)建viewmodel,并在里面生命協(xié)程作用域

viewmodel并不是協(xié)程所必須創(chuàng)建的,但屬于lifecycle的viewmodel,能感知生命周期,在生命周期的末尾取消掉協(xié)程,都不用去管內(nèi)存泄漏這些問題了,它不香么?

class MyViewModel:ViewModel() {
 /**
  * 這是此 ViewModel 運行的所有協(xié)程所用的任務。
  * 終止這個任務將會終止此 ViewModel 開始的所有協(xié)程。
  */
    private val viewModelJob = SupervisorJob()

 val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
 val ioScope = CoroutineScope(Dispatchers.IO + viewModelJob)
 override fun onCleared() { //不清楚的去百度一下viewmodel生命周期
  super.onCleared()
  viewModelJob.cancel()
 }

    //協(xié)程一共有幾種調(diào)度器,是有對應區(qū)別的,如下:
/*
Dispatchers 決定協(xié)程在哪個線程或線程池上運行(啟動和恢復)。最重要的選項有:

    Dispatchers.Defualt:被用來執(zhí)行 CPU 密集型操作
    Dispatchers.Main:被我們用來訪問主線程,例如在 Android、Swing 或者 JavaFX 上
    Dispatchers.Main.immediate:它和 Dispatchers.Main 運行在同一個線程上,但如果沒有必要,它不會重新調(diào)度
    Dispatchers.IO:被用來執(zhí)行一些阻塞線程的操作
    調(diào)用了 limitParallelism的 Dispatchers.IO 或者帶有自定義線程池的 Dispatcher.IO:我們用來處理大量的阻塞調(diào)用
    調(diào)用了 limitParallelism 并設置為1的 Dispatchers.Default 或 Dispatchers.IO,或具有單個線程的自定義調(diào)度器:被用來修改共享狀態(tài)
    Dispatchers.Unconfined:當我們不關(guān)心協(xié)程在哪個線程上被掛起時使用
*/
}

5.創(chuàng)建一個BaseActivity吧,通常我們的項目不都有它么,在里面設置我們將要用到的viewmodel以及serviceapi

abstract class BaseActivity  : AppCompatActivity(){
//熟悉吧,又用到了委托屬性,它只會加載一次,不用每次都計算,不香么
val myViewModel: MyViewModel by lazy {
        ViewModelProviders.of(this).get(MyViewModel::class.java)
    }
    val coroutineServiceApi: ServiceApi by lazy {
        RetrofitClient.getRetrofitClient().getCoroutineServiceApi()
    }
    //其它的代碼我就省略了,不重要
}

6.一切都有了,那么使用吧!

class TestKT :BaseActivity(){
    override fun getLayoutId(): Int {
        return R.layout.item_hot_cake_text
    }

    override fun initView() {
        myViewModel.ioScope.launch{ //這里我用的是Dispatchers.IO調(diào)度器,因為只是請求網(wǎng)絡讀寫數(shù)據(jù)呀,不用放到主線程
            var data = coroutineServiceApi.getUserGotoTest()
            initData(data)
        }
    }

//留意到了嗎?又是suspend關(guān)鍵字,協(xié)程體調(diào)用外部方法必須是suspend的,否則會報錯
    suspend fun initData(data: BaseResult<UserJumpConfigBean>){
        withContext(Dispatchers.Main){ //因為上面的調(diào)度器是IO線程的,但UI只能在主線程更新,所以這里要生命Main調(diào)度器,否則會報錯,如果上面調(diào)用的是uiScope那么這里就可以不用寫這個了
            tv_content.text = data.message
        }
    }

}

7.貼一下序列化的代碼

樓下有網(wǎng)友評論說Gson序列化失敗就會崩潰,這是因為你序列化的代碼沒有對接口的異常進行判斷,這個問題比較初級哈,鑒于此篇文章就是給初步使用協(xié)程請求網(wǎng)絡用的,就貼一下序列化的代碼吧,其實這個代碼是通用的,還用的是java版本

public class DsGsonConverterFactory extends Converter.Factory {

    public static final String TAG = DsGsonConverterFactory.class.getSimpleName();
    private final Gson gson;

    private DsGsonConverterFactory(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        this.gson = gson;
    }

    public static DsGsonConverterFactory create() {
        return create(new Gson());
    }

    public static DsGsonConverterFactory create(Gson gson) {
        return new DsGsonConverterFactory(gson);
    }


    @Nullable
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new GsonResponseBodyConverter<>(gson, adapter);
    }

    @Nullable
    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new GsonRequestBodyConverter(gson, adapter);
    }

    private final static class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {

        private static final MediaType MEDIA_TYPE = MediaType.parse("application/json;charset=UTF-8");
        private static final Charset UTF_8 = Charset.forName("UTF-8");

        private final Gson gson;
        private final TypeAdapter<T> adapter;

        GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
            this.gson = gson;
            this.adapter = adapter;
        }

        @Override
        public RequestBody convert(T value) throws IOException {
            Buffer buffer = new Buffer();
            Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);

            JsonWriter jsonWriter = gson.newJsonWriter(writer);
            adapter.write(jsonWriter, value);
            jsonWriter.close();
            return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
        }
    }

    private final static class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
        private final Gson gson;
        private final TypeAdapter<T> adapter;
        private final TypeAdapter<BaseResult> mExceptionAdapter;

        GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
            this.gson = gson;
            this.adapter = adapter;
            this.mExceptionAdapter = (TypeAdapter<BaseResult>) adapter;
        }

        @Override
        public T convert(ResponseBody value) throws IOException {
            String response = value.string();
            BaseResult baseResult = gson.fromJson(response, BaseResult.class);

            MediaType contentType = value.contentType();
            Charset charset = contentType != null ? contentType.charset(UTF_8) : UTF_8;
            InputStream inputStream = new ByteArrayInputStream(response.getBytes());
            Reader reader = new InputStreamReader(inputStream, charset);
            JsonReader jsonReader = gson.newJsonReader(reader);
            T entity = null;
            try {
                entity = adapter.read(jsonReader);
            } catch (JsonSyntaxException jsonSyntaxException) { //類型轉(zhuǎn)換錯誤
                KLogger.INSTANCE.e("json解析錯誤:" + jsonSyntaxException.getMessage());
                entity = (T) baseResult;
            } catch (Exception e) {
                e.printStackTrace();
                throw e;
            } finally {
                value.close();
                return entity;
            }
        }
    }

}

NOTO::寫在最后,至此,只要你有kotlin基礎,用過retrofit +okhttp,那么你現(xiàn)在已經(jīng)可以將網(wǎng)絡請求應用到實際項目中了。但是!但是!這還遠遠不夠的,本文的目的是期望你能快速上手運用協(xié)程,將異步的代碼用同步的邏輯來寫,這樣會使得代碼更簡潔,可讀性也更高,而且完全廢棄掉了Rxjava,也不用管什么回調(diào)地獄了,但你在會使用協(xié)程之后,就應該去關(guān)注一下更細節(jié)的東西;

比如:協(xié)程的作用域、協(xié)程里面需要再啟動協(xié)程、必要時取消協(xié)程等等。舉個實際項目中的例子,假設我們有兩個網(wǎng)絡請求,分別是接口A和接口B,接口B的請求依賴于接口A返回的字段,那么如果不用協(xié)程,我們是不是要寫接口A的回調(diào),然后在接口A里面去調(diào)用接口B。如果不是兩個網(wǎng)絡請求,是三個或者更多呢?代碼是不是看起來就很臃腫?那么協(xié)程就真香了,因為協(xié)程有async/await來處理并發(fā),試想一下,原本繁重的一個接口回調(diào)后再調(diào)另外一個接口,變成了如下代碼,是不是代碼量減少了,可讀性也越高了?

coroutineScope.launch(Dispatchers.IO) {
	val a1 = async{ 接口A() }
	val userInfo = a1.await()
	val a2 = async{ 接口B(userInfo.token) }
	val msgList = a2.await()
}

還有上面我不止一次提到的suspend關(guān)鍵字,它到底有什么用呢?文章來源地址http://www.zghlxwxcb.cn/news/detail-411331.html

到了這里,關(guān)于將kotlin協(xié)程用于網(wǎng)絡請求---完整實例,看這一篇就夠了的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關(guān)文章

  • 【Linux】在ubuntu18.04系統(tǒng)中配置網(wǎng)絡信息(超有用,完美解決,只看這一篇就行了)

    【Linux】在ubuntu18.04系統(tǒng)中配置網(wǎng)絡信息(超有用,完美解決,只看這一篇就行了)

    最近用centos搭建hadoop集群已經(jīng)熟練了,但是學習場景中更多的使用的是ubuntu環(huán)境,就安裝了ubuntu的環(huán)境進行搭建,結(jié)果ubuntu在很多地方與centos操作有較大區(qū)別,首先網(wǎng)絡配置就讓我折騰了半天,現(xiàn)在我將我已成功配置好的經(jīng)驗分享給大家 1.首先打開我們的VMware虛擬機,左上角

    2024年02月13日
    瀏覽(30)
  • 【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

    【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

    Kotlin 中的協(xié)程提供了一種全新處理并發(fā)的方式,可以在 Android 平臺上使用它來簡化異步執(zhí)行的代碼。協(xié)程是從 Kotlin 1.3 版本開始引入,但這一概念在編程世界誕生的黎明之際就有了,最早使用協(xié)程的編程語言可以追溯到 1967 年的 Simula 語言。 在過去幾年間,協(xié)程這個概念發(fā)展

    2024年02月07日
    瀏覽(38)
  • 微信小程序:服務器請求、上傳圖片和提交表單開發(fā)完整代碼實例

    該示例涉及服務器請求、上傳圖片、展示上傳的圖片,并提交表單,同時配合使用 WXML(微信小程序的前端頁面結(jié)構(gòu))、WXSS(樣式表)、以及 JavaScript(邏輯控制)。請注意,服務器端的實現(xiàn)將不在本示例范圍內(nèi),您需要根據(jù)實際需求創(chuàng)建后端 API 來處理請求和上傳的操作。

    2024年02月06日
    瀏覽(21)
  • Android---Retrofit實現(xiàn)網(wǎng)絡請求:Kotlin版

    Android---Retrofit實現(xiàn)網(wǎng)絡請求:Kotlin版

    在 Android 開發(fā)中,網(wǎng)絡請求是一個極為關(guān)鍵的部分。Retrofit 作為一個強大的網(wǎng)絡請求庫,能夠簡化開發(fā)流程,提供高效的網(wǎng)絡請求能力。 Retrofit 是一個建立在 OkHttp 基礎之上的網(wǎng)絡請求庫,能夠?qū)⑽覀兌x的 Java 接口轉(zhuǎn)化為相應的 HTTP請求,Retrofit 是適用于 Android 和 Java 的類

    2024年02月20日
    瀏覽(21)
  • Kotlin 協(xié)程一 —— 協(xié)程 Coroutine

    1.1.1基本定義 進程 進程是一個具有一定獨立功能的程序在一個數(shù)據(jù)集上的一次動態(tài)執(zhí)行的過程,是操作系統(tǒng)進行資源分配和調(diào)度的一個獨立單位,是應用程序運行的載體。 進程是資源分配的最小單位,在單核CPU中,同一時刻只有一個程序在內(nèi)存中被CPU調(diào)用運行。 線程 基本的

    2024年02月05日
    瀏覽(20)
  • [論文閱讀]PANet(PAFPN)——用于實例分割的路徑聚合網(wǎng)絡

    [論文閱讀]PANet(PAFPN)——用于實例分割的路徑聚合網(wǎng)絡

    Path Aggregation Network for Instance Segmentation 用于實例分割的路徑聚合網(wǎng)絡 論文網(wǎng)址:PANet 這篇論文提出了Path Aggregation Network (PANet),目的是增強基于proposal的實例分割框架中的信息流動。具體來說,論文提出了以下幾點改進: 增加自底向上的路徑(bottom-up path augmentation),用低層中的精確

    2024年02月05日
    瀏覽(20)
  • kotlin語法進階 - 協(xié)程(一)協(xié)程基礎

    kotlin語法進階 - 協(xié)程(一)協(xié)程基礎

    協(xié)程并不是一個新的概念,而是一個非常老的概念,很多語言都支持協(xié)程,建議去瀏覽器去了解一下協(xié)程的歷史和基本概念,這里我們只講一下kotlin中的協(xié)程的作用。 從代碼實現(xiàn)角度來看:kotlin協(xié)程底層是用線程實現(xiàn)的,是一個封裝完善供開發(fā)者使用的線程框架。kotlin的一個

    2024年02月09日
    瀏覽(21)
  • web3Js(干貨)(多簽的流程原理)看完這一篇就懂了(波場網(wǎng)絡-請勿用于除學習外其他用途)

    連接波場網(wǎng)絡: 其中APIKEY可以在官網(wǎng)獲取; 可以使用tronWeb.isConnected()判斷是否連接成功 創(chuàng)建離線波場地址: 該地址未激活,如果需要激活, 通常需要一定數(shù)量的 TRX(TRON 的本地代幣)用于支付激活費用; 等待區(qū)塊確定 就可以查看激活信息; 創(chuàng)建隨機助記詞與私鑰: 如何讓

    2024年02月04日
    瀏覽(99)
  • Kotlin協(xié)程-從一到多

    上一篇文章,我介紹了Kotlin協(xié)程的創(chuàng)建,使用,協(xié)作等內(nèi)容。本篇將引入更多的使用場景,繼續(xù)帶你走進協(xié)程世界。 常用編程語言都會內(nèi)置對同一類型不同對象的數(shù)據(jù)集表示,我們通常稱之為容器類。不同的容器類適用于不同的使用場景。Kotlin的 Flow 就是在異步計算的需求下

    2024年02月09日
    瀏覽(19)
  • Android Kotlin 協(xié)程初探

    維基百科:協(xié)程,英文Coroutine [k?ru’tin] (可入廳),是計算機程序的一類組件,推廣了協(xié)作式多任務的子程序,允許執(zhí)行被掛起與被恢復。 作為Google欽定的Android開發(fā)首選語言Kotlin,協(xié)程并不是 Kotlin 提出來的新概念,目前有協(xié)程概念的編程語言有Lua語言、Python語言、Go語言

    2024年02月08日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包