亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

[譯] 在 Android 使用協(xié)程(part III) - 在實(shí)際工作中使用

番茄西紅柿 / 1810人閱讀

摘要:通過實(shí)現(xiàn)一次請(qǐng)求來解釋使用協(xié)程中的實(shí)際問題是這篇文章的重點(diǎn)。當(dāng)接收一個(gè)新事件時(shí),啟動(dòng)一個(gè)新的協(xié)程來對(duì)列表進(jìn)行排序,并在響應(yīng)時(shí)更新。在中啟動(dòng)協(xié)程作為一般模式。因此,在默認(rèn)情況下,在存儲(chǔ)庫(kù)中啟動(dòng)的任何協(xié)程都會(huì)泄露。


原文鏈接:Coroutines On Android (part III): Real work

原文作者:Sean McQuillan

這是一篇關(guān)于在 Android 上使用協(xié)程的系列文章之一。通過實(shí)現(xiàn)一次請(qǐng)求來解釋使用協(xié)程中的實(shí)際問題是這篇文章的重點(diǎn)。

本系列的其他文章:

[譯] 在 Android 使用協(xié)程(part I) - 協(xié)程的背景知識(shí)

[譯] 在 Android 使用協(xié)程(part II) - 入門指南

使用協(xié)程解決實(shí)際問題

本系列的第 1 部分和第 2 部分重點(diǎn)介紹了如何使用協(xié)程來簡(jiǎn)化代碼、在 Android 上提供主線程安全調(diào)用以及避免協(xié)程泄露。有了這個(gè)背景,協(xié)程看起來是一個(gè)既可以用于后臺(tái)處理,又可以簡(jiǎn)化 Callback 的很好解決方案。

到目前為止,我們主要關(guān)注的是「什么是協(xié)程」以及「如何管理它們」。在這篇文章中,我們將看看如何使用它們來完成一些真正的任務(wù)。協(xié)程是一種通用的編程語(yǔ)言特性,與函數(shù)處于同一級(jí)別,因此,你可以使用它們來實(shí)現(xiàn)任何使用函數(shù)和對(duì)象實(shí)現(xiàn)的功能。然而,有兩種類型的任務(wù)總是出現(xiàn)在實(shí)際代碼中,協(xié)程是一種很好的解決方案:

    一次性請(qǐng)求 它們總是在得到響應(yīng)時(shí)認(rèn)為請(qǐng)求完成了,所以每次調(diào)用時(shí)都會(huì)重新運(yùn)行的請(qǐng)求

    流請(qǐng)求 它們不會(huì)在得到第一個(gè)響應(yīng)時(shí)就認(rèn)為請(qǐng)求完成了,還會(huì)繼續(xù)觀察改變并將其報(bào)告給調(diào)用者

協(xié)程是這兩個(gè)任務(wù)的一個(gè)很好的解決方案。在這篇文章中,我們將深入研究一次性請(qǐng)求,并探索如何在 Android 上用協(xié)程實(shí)現(xiàn)它們。

一次性請(qǐng)求

每次調(diào)用一個(gè)一次性請(qǐng)求都會(huì)執(zhí)行一次,并在響應(yīng)時(shí)完成。此模式與常規(guī)函數(shù)調(diào)用相同——被調(diào)用,執(zhí)行一些操作,然后返回。由于與函數(shù)調(diào)用的相似性,它們往往比流請(qǐng)求更容易理解。

每次調(diào)用一個(gè)一次性請(qǐng)求時(shí)都會(huì)執(zhí)行一次。一旦得到響應(yīng),就停止執(zhí)行。

對(duì)于一次性請(qǐng)求的示例,請(qǐng)考慮瀏覽器如何加載此頁(yè)面。當(dāng)你點(diǎn)擊到這篇文章的鏈接時(shí),瀏覽器向服務(wù)器發(fā)送了一個(gè)網(wǎng)絡(luò)請(qǐng)求來加載頁(yè)面。一旦頁(yè)面被傳輸?shù)侥愕臑g覽器,它就停止與后端通信——它已經(jīng)獲取到需要的所有數(shù)據(jù)。如果服務(wù)器修改了這篇文章,除非你刷新頁(yè)面否則新的修改將不會(huì)顯示在瀏覽器中。

因此,雖然它們?nèi)狈α髡?qǐng)求的實(shí)時(shí)推送功能,但一次性請(qǐng)求仍舊非常強(qiáng)大。在 Android 應(yīng)用中,有很多事情可以通過一次性請(qǐng)求來解決,比如獲取、存儲(chǔ)或更新數(shù)據(jù)。對(duì)于排序列表之類的事情,它也是一種很好的模式。

問題:顯示已排序的列表

讓我們通過查看如何顯示排序列表來研究一次性請(qǐng)求。為了讓示例更加具體,我們構(gòu)建了一個(gè)「存貨清單」的應(yīng)用,供商店員工使用。它將用于根據(jù)產(chǎn)品最后一次進(jìn)貨的時(shí)間查找產(chǎn)品——他們希望能夠?qū)α斜磉M(jìn)行升序和降序排序。因?yàn)橛泻芏喈a(chǎn)品,排序產(chǎn)品可能需要一秒鐘,所以我們將使用協(xié)程來避免阻塞主線程!

在這個(gè)應(yīng)用中,所有的產(chǎn)品都存儲(chǔ)在一個(gè) Room 數(shù)據(jù)庫(kù)中。這是一個(gè)很好的用例,因?yàn)樗恍枰婕熬W(wǎng)絡(luò)請(qǐng)求,所以我們可以關(guān)注模式。盡管這個(gè)示例比較簡(jiǎn)單,因?yàn)樗皇褂镁W(wǎng)絡(luò),但是它展示了實(shí)現(xiàn)一次性請(qǐng)求所需的模式。

要使用協(xié)程實(shí)現(xiàn)這個(gè)請(qǐng)求,你將把協(xié)程引入到 ViewModel、Repository 和 Dao。讓我們逐個(gè)瀏覽一下,看看如何將它們與協(xié)程集成在一起。

class ProductsViewModel(val productsRepository: ProductsRepository): ViewModel() {
   val _sortedProducts = MutableLiveData>()
   val sortedProducts: LiveData> = _sortedProducts

   /**
    * 當(dāng)用戶點(diǎn)擊 sort 按鈕時(shí)調(diào)用,由 UI 層調(diào)用
    */
   fun onSortAscending() = sortPricesBy(ascending = true)
   fun onSortDescending() = sortPricesBy(ascending = false)

   private fun sortPricesBy(ascending: Boolean) {
       viewModelScope.launch {
           // 掛起和恢復(fù)使這個(gè)數(shù)據(jù)庫(kù)請(qǐng)求確保主線程安全
           // 所以我們的 ViewModel 不需要擔(dān)心線程
           _sortedProducts.value =
                   productsRepository.loadSortedProducts(ascending)
       }
   }
}

ProductsViewModel 負(fù)責(zé)從 UI 層接收事件,然后向存儲(chǔ)庫(kù)請(qǐng)求更新后的數(shù)據(jù)。它使用 LiveData 保存當(dāng)前已排序的列表,以便讓 UI 顯示。當(dāng) sortProductsBy 接收一個(gè)新事件時(shí),啟動(dòng)一個(gè)新的協(xié)程來對(duì)列表進(jìn)行排序,并在響應(yīng)時(shí)更新 LiveData。ViewModel 通常是這個(gè)體系結(jié)構(gòu)中啟動(dòng)大多數(shù)協(xié)程的正確位置,因?yàn)樗梢栽?onCleared中取消協(xié)程。如果用戶離開界面,它們通常不再需要工作。

如果你還不經(jīng)常使用 LiveData,請(qǐng)查看 @CeruleanOtter發(fā)布的這篇很棒的文章,它介紹了如何為 UI 存儲(chǔ)數(shù)據(jù).

一個(gè)簡(jiǎn)單的 ViewModel 示例 (ViewModels : A Simple Example)

這是 Android 上協(xié)程的一般模式。由于 Android 框架不能調(diào)用掛起函數(shù),因此你需要配合一個(gè)協(xié)程來響應(yīng) UI 事件。最簡(jiǎn)單的辦法是事件發(fā)生時(shí)啟動(dòng)一個(gè)新的協(xié)程,而在 ViewModel 做這件事比較合適。

在 ViewModel 中啟動(dòng)協(xié)程作為一般模式。

ViewModel 使用 ProductsRepository 來實(shí)際獲取數(shù)據(jù)。來看它是這樣做的:

class ProductsRepository(val productsDao: ProductsDao) {

  /**
    * 這是一個(gè)"常規(guī)"掛起函數(shù),這意味著調(diào)用者必須處于一個(gè)協(xié)程中。存儲(chǔ)層不負(fù)責(zé)啟動(dòng)或
    * 停止協(xié)程,因?yàn)樗鼪]有一個(gè)合適的生命周期來取消不必要的工作。
    * 這可以是從 Dispatchers.Main 調(diào)用的,而且是主線程安全的,因?yàn)?Room 將為我們負(fù)責(zé)
    * 主線程安全。
    */
   suspend fun loadSortedProducts(ascending: Boolean): List {
       return if (ascending) {
           productsDao.loadProductsByDateStockedAscending()
       } else {
           productsDao.loadProductsByDateStockedDescending()
       }
   }
}

ProductsRepository 為產(chǎn)品交互提供了一個(gè)合理的接口。在這個(gè)應(yīng)用程序中,由于所有內(nèi)容都在本地的 Room 數(shù)據(jù)庫(kù)中,所以他只是為 @Dao 提供了一個(gè)很好的接口,對(duì)于不同的排序,@Dao 有兩個(gè)不同的函數(shù)。

存儲(chǔ)層是 Android 架構(gòu)體系中一個(gè)可選部分——但如果你的應(yīng)用有它或類似的層,它應(yīng)該更愿意暴露常規(guī)掛起函數(shù)。因?yàn)榇鎯?chǔ)層沒有一個(gè)天然的生命周期——它只是一個(gè)對(duì)象——它沒有辦法清理工作。因此,在默認(rèn)情況下,在存儲(chǔ)庫(kù)中啟動(dòng)的任何協(xié)程都會(huì)泄露。

除了避免泄露之外,通過暴露常規(guī)掛起函數(shù),還可以很容易地在不同的上下文中復(fù)用存儲(chǔ)庫(kù)。任何知道如何創(chuàng)造協(xié)程的東西都可以調(diào)用 loadSortedProducts 。例如,Workmanager 調(diào)度的后臺(tái) Job 可以直接調(diào)用它。

存儲(chǔ)庫(kù)應(yīng)該暴露出主線程安全的常規(guī)掛起函數(shù)。

注意:一些后臺(tái)保存操作可能會(huì)希望用戶離開界面后繼續(xù)執(zhí)行——在沒有生命周期的情況下運(yùn)行這些保存是有意義的。在大多數(shù)其他情況下,viewModelScope 是一個(gè)合理的選擇。

繼續(xù)看 ProductsDao,它看起來是這樣的:

@Dao
interface ProductsDao {
   // 因?yàn)檫@是掛起的,Room 將使用它自己的調(diào)度器以主線程安全的方式運(yùn)行這個(gè)查詢
   @Query("select * from ProductListing ORDER BY dateStocked ASC")
   suspend fun loadProductsByDateStockedAscending(): List

   // 因?yàn)檫@是掛起的,Room 將使用它自己的調(diào)度器以主線程安全的方式運(yùn)行這個(gè)查詢
   @Query("select * from ProductListing ORDER BY dateStocked DESC")
   suspend fun loadProductsByDateStockedDescending(): List
}  

ProductsDao 是一個(gè) Room @Dao ,它公開了兩個(gè)掛起函數(shù)。由于函數(shù)被suspend 標(biāo)記,Room 確保它們是主線程安全的。這意味著你可以直接從 Dispatchers.Main 來調(diào)用它們。

如果你還沒有在 Room 中看到協(xié)程,請(qǐng)查看 @FMuntenescu的這篇很棒的文章

Room

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/7055.html

相關(guān)文章

  • [] WorkManager 基礎(chǔ)入門

    摘要:讓我們探討一下如何確保你的工作脫離主線程運(yùn)行并保證執(zhí)行。這確保在默認(rèn)情況下,你的工作是同步運(yùn)行的,并且在主線程之外運(yùn)行。這是應(yīng)該脫離主線程運(yùn)行的工作,但是,因?yàn)樗c直接相關(guān),所以如果關(guān)閉應(yīng)用程序則不需要繼續(xù)。 原文地址:WorkManager Basics 原文作者:Lyla Fujiwara 譯文出自:掘金翻譯計(jì)劃 本文永久鏈接:github.com/xitu/gold-m… 譯者:Ri...

    番茄西紅柿 評(píng)論0 收藏0
  • []教程:如何使用Rollup打包樣式文件并添加LiveReload

    摘要:通過這個(gè)教程學(xué)習(xí)如何使用打包工具配合來取代或處理樣式文件。使用這個(gè)命令安裝插件更新。如果你沒有項(xiàng)目的副本,你可以通過這條命令克隆在結(jié)束這個(gè)狀態(tài)下的項(xiàng)目為添加監(jiān)聽插件。在代碼塊內(nèi),添加如下內(nèi)容簡(jiǎn)單起見我省略了文件的大部分內(nèi)容 通過這個(gè)教程學(xué)習(xí)如何使用JavaScript打包工具Rollup配合PostCSS來取代Grunt或Gulp處理樣式文件。 上一篇文章中,我們完成了使用Rollup...

    garfileo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<