<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Kotlin協(xié)程場(chǎng)景化學(xué)習(xí)

          共 6259字,需瀏覽 13分鐘

           ·

          2021-01-20 23:37

          何為Kotlin協(xié)程?

          協(xié)程是一種并發(fā)設(shè)計(jì)模式,Kotlin協(xié)程是一個(gè)線程框架。

          為什么需要Kotlin協(xié)程?

          提供方便的線程操作API,編寫邏輯清晰且簡(jiǎn)潔的線程代碼。

          協(xié)程是Google在 Android 上進(jìn)行異步編程的推薦解決方案。具有如下特點(diǎn):

          • 輕量:您可以在單個(gè)線程上運(yùn)行多個(gè)協(xié)程,因?yàn)閰f(xié)程支持掛起,不會(huì)使正在運(yùn)行協(xié)程的線程阻塞。掛起比阻塞節(jié)省內(nèi)存,且支持多個(gè)并行操作。
          • 內(nèi)存泄漏更少:使用結(jié)構(gòu)化并發(fā)機(jī)制在一個(gè)作用域內(nèi)執(zhí)行多項(xiàng)操作。
          • 內(nèi)置取消支持:取消操作會(huì)自動(dòng)在運(yùn)行中的整個(gè)協(xié)程層次結(jié)構(gòu)內(nèi)傳播。
          • Jetpack 集成:許多 Jetpack 庫(kù)都包含提供全面協(xié)程支持的擴(kuò)展。某些庫(kù)還提供自己的協(xié)程作用域,可供您用于結(jié)構(gòu)化并發(fā)。

          如何使用Kotlin協(xié)程

          添加依賴

          dependencies?{
          ????implementation?'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
          }

          使用場(chǎng)景

          啟動(dòng)協(xié)程

          若我們需要執(zhí)行一個(gè)簡(jiǎn)單的后臺(tái)(或者前臺(tái))任務(wù),通過(guò)GlobalScope.launch可以快速的啟動(dòng)一個(gè)協(xié)程來(lái)處理業(yè)務(wù)邏輯,同時(shí),也可以通過(guò)Dispatchs來(lái)指定線程類型:Dispatchers.Default、Dispatchers.IO、Dispatchers.Main、Dispatchers.Unconfined

          GlobalScope.launch(Dispatchers.IO)?{
          ????delay(1000)
          ????Log.d(TAG,?"processIO?in?${Thread.currentThread().name}")
          }

          切換線程

          主線程 => IO線程 => 主線程。這種場(chǎng)景開(kāi)發(fā)過(guò)程中使用最多,比如后臺(tái)獲取一張照片,然后前臺(tái)顯示。

          //?主線程內(nèi)啟動(dòng)一個(gè)協(xié)程
          GlobalScope.launch(Dispatchers.Main)?{
          ????//?切換到IO線程
          ????withContext(Dispatchers.IO)?{
          ????????delay(1000)
          ????????Log.d(TAG,?"processIO?in?${Thread.currentThread().name}")
          ????}
          ????//?自動(dòng)切回主線程
          ????Log.d(TAG,?"processUI?in?${Thread.currentThread().name}")
          }

          運(yùn)行結(jié)果:

          2021-01-02?18:38:23.812?15506-15535/tech.kicky.coroutine?D/Coroutine?Sample:?processIO?in?DefaultDispatcher-worker-1
          2021-01-02?18:38:23.813?15506-15506/tech.kicky.coroutine?D/Coroutine?Sample:?processUI?in?main

          取消協(xié)程

          private?fun?cancelCoroutine()?{
          ????val?job?=?GlobalScope.launch(Dispatchers.IO)?{
          ????????for?(i?in?0..10000)?{
          ????????????delay(1)
          ????????????Log.d(TAG,?"count?=?$i")
          ????????}
          ????}
          ????Thread.sleep(30)
          ????job.cancel()
          ????Log.d(TAG,?"Coroutine?Cancel")
          }

          執(zhí)行結(jié)果如下:

          2021-01-02?18:53:37.680?23240-23279/tech.kicky.coroutine?D/Coroutine?Sample:?count?=?0
          2021-01-02?18:53:37.682?23240-23278/tech.kicky.coroutine?D/Coroutine?Sample:?count?=?1
          2021-01-02?18:53:37.685?23240-23280/tech.kicky.coroutine?D/Coroutine?Sample:?count?=?2
          2021-01-02?18:53:37.687?23240-23280/tech.kicky.coroutine?D/Coroutine?Sample:?count?=?3
          2021-01-02?18:53:37.689?23240-23280/tech.kicky.coroutine?D/Coroutine?Sample:?count?=?4
          2021-01-02?18:53:37.690?23240-23280/tech.kicky.coroutine?D/Coroutine?Sample:?count?=?5
          2021-01-02?18:53:37.693?23240-23280/tech.kicky.coroutine?D/Coroutine?Sample:?count?=?6
          2021-01-02?18:53:37.696?23240-23240/tech.kicky.coroutine?D/Coroutine?Sample:?Coroutine?Cancel

          LifecycleOwner配合使用

          由于Kotlin協(xié)程主要作用是處理線程操作,若處理不當(dāng)會(huì)出現(xiàn)內(nèi)存泄露等問(wèn)題,如Activity或者Fragment已銷毀,但是界面內(nèi)的協(xié)程卻依舊在執(zhí)行,就會(huì)產(chǎn)生內(nèi)存泄露的問(wèn)題。所以,我們?cè)诮缑驿N毀時(shí),必須取消界面內(nèi)的協(xié)程操作。我們可以自己在界面銷毀時(shí)調(diào)用cancel()方法,但是無(wú)良好的編程習(xí)慣就很容易被忽略。建議采用Google給我們提供的擴(kuò)展方法

          implementation?"androidx.activity:activity-ktx:1.1.0"
          implementation?"androidx.fragment:fragment-ktx:1.2.5"
          private?fun?lifecycleCoroutine()?{
          ????//?主線程內(nèi)啟動(dòng)一個(gè)協(xié)程
          ????lifecycleScope.launch?{
          ????????//?切換到IO線程
          ????????withContext(Dispatchers.IO)?{
          ????????????delay(1000)
          ????????????Log.d(TAG,?"processIO?in?${Thread.currentThread().name}")
          ????????}
          ????????//?自動(dòng)切回主線程
          ????????Log.d(TAG,?"processUI?in?${Thread.currentThread().name}")
          ????}
          }

          注意:

          1. lifecycleScope.launch()默認(rèn)就是在主線程啟動(dòng)協(xié)程;

          2. lifecycleScope內(nèi)的協(xié)程在Lifecycle為destroyed狀態(tài)時(shí)會(huì)自動(dòng)取消。

          3.lifecycleScope還有一些其他的擴(kuò)展方法,如launchWhenCreated、launchWhenStarted、launchWhenResumed等,用法從方法名上看很明顯

          ViewModel配合使用

          協(xié)程與LifecycleOwner配合使用解決的是界面生命周期變化過(guò)程中協(xié)程的處理問(wèn)題。但是針對(duì)屏幕旋轉(zhuǎn)這種界面重建的場(chǎng)景,ViewModel對(duì)象的存在時(shí)間比LifecycleOwner要持久。雖然界面需要重建,但是協(xié)程不一定要被取消,這個(gè)需要結(jié)合具體需求考慮。

          fun?viewModelCoroutine()?{
          ????viewModelScope.launch?{
          ????????Log.d("Coroutine?Sample",?Thread.currentThread().name)
          ????}
          }

          注意:

          1. viewModelScope.launch()默認(rèn)也是在主線程啟動(dòng)協(xié)程;

          2. viewModelScope內(nèi)的協(xié)程在ViewModel將被onCleared時(shí)會(huì)自動(dòng)取消。

          Retrofit真香組合

          說(shuō)重點(diǎn),Retrofit 2.6之后的版本支持使用Kotlin的協(xié)程。那么,具體如何支持?

          • 添加依賴
          implementation?"com.squareup.retrofit2:retrofit:2.9.0"
          implementation?"com.squareup.retrofit2:converter-gson:2.9.0"
          • 添加網(wǎng)絡(luò)權(quán)限
          <uses-permission?android:name="android.permission.INTERNET"?/>
          • Retrofit
          object?Retrofitance?{
          ????private?val?client:?OkHttpClient?by?lazy?{
          ????????OkHttpClient.Builder()
          ????????????.build()
          ????}

          ????private?val?retrofitance:?Retrofit?by?lazy?{
          ????????Retrofit.Builder()
          ????????????.baseUrl("https://www.wanandroid.com")
          ????????????.addConverterFactory(GsonConverterFactory.create())
          ????????????.client(client)
          ????????????.build()
          ????}

          ????val?wanAndroidApi:?WanAndroidApi?by?lazy?{
          ????????retrofitance.create(WanAndroidApi::class.java)
          ????}
          }
          • API
          interface?WanAndroidApi?{

          ????@GET("/banner/json")
          ????suspend?fun?banners():?WanAndroidRoot
          }

          重點(diǎn)關(guān)注API里的suspend關(guān)鍵字。suspend是掛起的意思,提醒開(kāi)發(fā)者此方法為耗時(shí)方法。

          • 執(zhí)行網(wǎng)絡(luò)請(qǐng)求
          class?MainViewModel?:?ViewModel()?{

          ????val?banners?=?MutableLiveData>()

          ????fun?viewModelCoroutine()?{
          ????????viewModelScope.launch(Dispatchers.IO)?{
          ????????????val?result?=?Retrofitance.wanAndroidApi.banners()
          ????????????banners.postValue(result.data)
          ????????}
          ????}
          }
          private?val?viewModel?by?viewModels()

          override?fun?onCreate(savedInstanceState:?Bundle?)?{
          ????super.onCreate(savedInstanceState)
          ????setContentView(binding.root)
          ????viewModel.banners.observe(this,?{
          ????????val?content:?List?=?it.map?{?banner?->
          ????????????banner.title
          ????????}
          ????????binding.text.text?=?content.toTypedArray().contentToString()
          ????})
          ????viewModel.viewModelCoroutine()
          }

          Retrofit請(qǐng)求依賴

          針對(duì)存在依賴關(guān)系的網(wǎng)絡(luò)請(qǐng)求,未使用協(xié)程之前,我們需要在回調(diào)中處理,一層兩層尚可,層次多了就容易凌亂。使用協(xié)程,按照順序編寫代碼,簡(jiǎn)潔清晰。

          fun?viewModelSequenceRequest()?{
          ????viewModelScope.launch(Dispatchers.IO)?{
          ????????val?start?=?System.currentTimeMillis()
          ????????//?先請(qǐng)求首頁(yè)Banners
          ????????val?result?=?Retrofitance.wanAndroidApi.banners()
          ????????banners.postValue(result.data)
          ????????//?再請(qǐng)求熱鍵,只要是順序執(zhí)行即可且上一次的請(qǐng)求結(jié)果已拿到即可滿足我們的使用場(chǎng)景。
          ????????val?keys?=?Retrofitance.wanAndroidApi.hotKeys()
          ????????hotKeys.postValue(keys.data)
          ????????Log.d("Coroutine?Sample",?(System.currentTimeMillis()?-?start).toString())
          ????}
          }

          Retrofit并發(fā)結(jié)果合并

          針對(duì)多并發(fā)執(zhí)行,結(jié)果統(tǒng)一處理,然后再執(zhí)行其他內(nèi)容的場(chǎng)景。未使用協(xié)程之前,我們可以采用RxJava的zip操作符處理。協(xié)程async/await輕松勝任。

          fun?viewModelAsync()?{
          ????viewModelScope.launch(Dispatchers.IO)?{
          ????????val?start?=?System.currentTimeMillis()
          ????????val?result?=?async?{?Retrofitance.wanAndroidApi.banners()?}
          ????????val?keys?=?async?{?Retrofitance.wanAndroidApi.hotKeys()?}
          ????????Log.d(
          ????????????????"Coroutine?Sample",
          ????????????????(result.await().data.size?+?keys.await().data.size).toString()
          ????????????)
          ????????Log.d("Coroutine?Sample",?(System.currentTimeMillis()?-?start).toString())
          ????}
          }

          和上一個(gè)例子的代碼相同,但是執(zhí)行時(shí)間卻會(huì)少很多,因?yàn)檫@個(gè)不是順序執(zhí)行而是并發(fā)執(zhí)行。

          總結(jié)

          個(gè)人認(rèn)為Kotlin協(xié)程的基本使用重點(diǎn)關(guān)注如下三個(gè)方面:

          • 線程切換
          • 如何避免內(nèi)存泄露(與LifecycleOwner、ViewModel等配合使用)
          • 搭配Retrofit

          當(dāng)然,Kotlin Coroutine庫(kù)里面還有很多操作符和方法有待探索,即學(xué)即用。

          源碼

          https://github.com/onlyloveyd/LearningCoroutine

          瀏覽 63
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  北条麻纪一区二区三区在线观看视频 | 国产理论视频在线观看 | a级免费网站 | 中文无码日韩无码 | 欧美另类激情总和网 |