成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

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

番茄西紅柿 / 1566人閱讀

摘要:讓我們探討一下如何確保你的工作脫離主線程運(yùn)行并保證執(zhí)行。這確保在默認(rèn)情況下,你的工作是同步運(yùn)行的,并且在主線程之外運(yùn)行。這是應(yīng)該脫離主線程運(yùn)行的工作,但是,因為它與直接相關(guān),所以如果關(guān)閉應(yīng)用程序則不需要繼續(xù)。


原文地址:WorkManager Basics

原文作者:Lyla Fujiwara

譯文出自:掘金翻譯計劃

本文永久鏈接:github.com/xitu/gold-m…

譯者:Rickon

校對者:Feximin

插圖來自 Virginia Poltrack

歡迎來到我們 WorkManager 系列的第二篇文章。WorkManager 是一個 Android Jetpack 庫,當(dāng)滿足工作的約束條件時,用來運(yùn)行可延遲、需要保障的后臺工作。對于許多類型的后臺工作,WorkManager 是當(dāng)前的最佳實(shí)踐方案。在第一篇博文中,我們討論了 WorkManager 是什么以及何時使用 WorkManager。

在這篇博文中,我將介紹:

將你的后臺任務(wù)定義為工作

定義特定的工作應(yīng)該如何運(yùn)行

運(yùn)行你的工作

使用鏈進(jìn)行存在依賴的工作

監(jiān)視你的工作的狀態(tài)

我還將解釋 WorkManager 幕后發(fā)生的事情,以便你可以就如何使用它做出明智的決定。

從一個例子開始

假設(shè)你有一個圖片編輯應(yīng)用,可讓你給圖像加上濾鏡并將其上傳到網(wǎng)絡(luò)讓全世界看到。你希望創(chuàng)建一系列后臺任務(wù),這些任務(wù)用于濾鏡,壓縮圖像和之后的上傳。在每個環(huán)節(jié),都有一個需要檢查的約束——給圖像加濾鏡時要有足夠的電量,壓縮圖像時要有足夠的存儲空間,以及上傳圖像時要有網(wǎng)絡(luò)連接。

這個例子如上圖所示

這個例子正是具有以下特點(diǎn)的任務(wù):

可延遲的,因為你不需要它立即執(zhí)行,而且實(shí)際上可能希望等待某些約束被滿足(例如等待網(wǎng)絡(luò)連接)。

需要確保能夠運(yùn)行,無論應(yīng)用程序是否退出,因為如果加了濾鏡后的圖像永遠(yuǎn)沒能與世界共享,你的用戶會非常不滿意!

這些特點(diǎn)使我們的圖像加濾鏡和上傳任務(wù)成為 WorkManager 的完美用例。

添加 WorkManager 依賴

本文使用 Kotlin 書寫代碼,使用 KTX 庫(KoTlin eXtensions)。KTX 版本的庫提供了 擴(kuò)展函數(shù) 為了更簡潔和習(xí)慣的使用 Kotlin。你可以添加如下依賴來使用 KTX 版本的 WorkManager:

dependencies {
 def work_version = "1.0.0-beta02"
 implementation "android.arch.work:work-runtime-ktx:$work_version"
}

你可以在 這里](developer.android.com/topic/libra…) 到該庫的最新版本。如果你想使用 Java 依賴,那就移除“-ktx”。

定義你的 work 做什么

在我們將多個任務(wù)連接在一起之前,讓我們關(guān)注如何執(zhí)行一項工作。我將會著重細(xì)說上傳任務(wù)。首先,你需要創(chuàng)建自己的 Worker 實(shí)現(xiàn)類。我將會把我們的類命名為 UploadWorker,然后重寫 doWork() 方法。

Workers:

定義你的工作實(shí)際做了什么。

接受輸入并產(chǎn)生輸出。輸入和輸出都以鍵值對表示。

始終返回表示成功,失敗或重試的值。

這是一個示例,展示了如何實(shí)現(xiàn)上傳圖像的 Worker

class UploadWorker(appContext: Context, workerParams: WorkerParameters)
    : Worker(appContext, workerParams) {

    override fun doWork(): Result {
        try {
            // Get the input
            val imageUriInput = inputData.getString(Constants.KEY_IMAGE_URI)

            // Do the work
            val response = upload(imageUriInput)

            // Create the output of the work
            val imageResponse = response.body()
            val imgLink = imageResponse.data.link
            // workDataOf (part of KTX) converts a list of pairs to a [Data] object.
            val outputData = workDataOf(Constants.KEY_IMAGE_URI to imgLink)

            return Result.success(outputData)

        } catch (e: Exception) {
            return Result.failure()
        }
    }

    fun upload(imageUri: String): Response {
        TODO(“Webservice request code here”)
        // Webservice request code here; note this would need to be run
        // synchronously for reasons explained below.
    }

}

有兩點(diǎn)需要注意:

輸入和輸出是作為 Data 傳遞,它本質(zhì)上是原始類型和數(shù)組的映射。Data 對象應(yīng)該相當(dāng)小 —— 實(shí)際上可以輸入/輸出的總大小有限制。這由 MAX_DATA_BYTES 設(shè)置。如果您需要將更多數(shù)據(jù)傳入和傳出 Worker,則應(yīng)將數(shù)據(jù)放在其他地方,例如 Room database。作為一個例子,我傳入上面圖像的 URI,而不是圖像本身。

在代碼中,我展示了兩個返回示例:Result.success()Result.failure()。還有一個 Result.retry() 選項,它將在之后的時間再次重試你的工作。

定義您的 work 應(yīng)該如何運(yùn)行

一方面 Worker 定義工作的作用,另一方面 WorkRequest 定義應(yīng)該如何以及何時運(yùn)行工作。

以下是為 UploadWorker 創(chuàng)建 OneTimeWorkRequest 的示例。也可以有重復(fù)性的 PeriodicWorkRequest

// workDataOf (part of KTX) converts a list of pairs to a [Data] object.
val imageData = workDataOf(Constants.KEY_IMAGE_URI to imageUriString)

val uploadWorkRequest = OneTimeWorkRequestBuilder()
        .setInputData(imageData)
        .build()

WorkRequest 將輸入 imageData: Data 對象,并盡快運(yùn)行。

假設(shè) UploadWork 并不總是應(yīng)該立即運(yùn)行 —— 它應(yīng)該只在設(shè)備有網(wǎng)絡(luò)連接時運(yùn)行。你可以通過添加 Constraints 對象來完成此操作。你可以創(chuàng)建這樣的約束:

val constraints = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .build()

以下是其他受支持約束的示例:

val constraints = Constraints.Builder()
        .setRequiresBatteryNotLow(true)
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .setRequiresCharging(true)
        .setRequiresStorageNotLow(true)
        .setRequiresDeviceIdle(true)
        .build()

最后,還記得 Result.retry() 嗎?我之前說過,如果 Worker 返回 Result.retry(),WorkManager 將重新計劃工作。你可以在創(chuàng)建新的 WorkRequest 時自定義退避條件。這允許你定義何時應(yīng)重試運(yùn)行。

退避條件由兩個屬性定義:

BackoffPolicy,默認(rèn)為指數(shù)性的,但是可以設(shè)置為線性。

持續(xù)時間,默認(rèn)為 30 秒。

用于對上傳工作進(jìn)行排隊的組合代碼如下,包括約束,輸入和自定義退避策略:

// Create the Constraints
val constraints = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .build()

// Define the input
val imageData = workDataOf(Constants.KEY_IMAGE_URI to imageUriString)

// Bring it all together by creating the WorkRequest; this also sets the back off criteria
val uploadWorkRequest = OneTimeWorkRequestBuilder()
        .setInputData(imageData)
        .setConstraints(constraints)        
        .setBackoffCriteria(
                BackoffPolicy.LINEAR, 
                OneTimeWorkRequest.MIN_BACKOFF_MILLIS, 
                TimeUnit.MILLISECONDS)
        .build()
運(yùn)行 work

這些都很好,但你還沒有真正調(diào)度好你的工作去運(yùn)行。以下是告訴 WorkManager 調(diào)度工作所需的一行代碼:

WorkManager.getInstance().enqueue(uploadWorkRequest)

你首先需要獲取 WorkManager 的實(shí)例,這是一個負(fù)責(zé)執(zhí)行你的工作的單例。調(diào)用 enqueue 來啟動 WorkManager 跟蹤和調(diào)度工作的整個過程。

在幕后 —— 工作是怎么運(yùn)行的

那么,WorkManager 能為您做些什么呢?默認(rèn)情況下,WorkManager 會:

脫離主線程運(yùn)行你的工作(假設(shè)你正在繼承 Worker 類,如上面的 UploadWorker 所示)。

保障 你的工作將會運(yùn)行(即使你重啟設(shè)備或應(yīng)用程序退出,它也不會忘記運(yùn)行你的工作)。

根據(jù)用戶 API 級別的最佳實(shí)踐運(yùn)行(如上一篇文章所述)。

讓我們探討一下 WorkManager 如何確保你的工作脫離主線程運(yùn)行并保證執(zhí)行。在幕后,WorkManager 包括以下部分:

內(nèi)部 TaskExecutor:一個單線程 Executor,處理所有排隊工作的請求。如果您不熟悉 Executors,可以在這里閱讀更多相關(guān)信息。

WorkManager 數(shù)據(jù)庫:一個本地數(shù)據(jù)庫,可跟蹤所有工作的所有信息和狀態(tài)。這包括工作的當(dāng)前狀態(tài),工作的輸入和輸出以及對工作的任何約束限制。此數(shù)據(jù)庫使 WorkManager 能夠保證你的工作能夠完成 —— 如果你的用戶的設(shè)備重新啟動并且工作中斷,則可以從數(shù)據(jù)庫中提取工作的所有詳細(xì)信息,并在設(shè)備再次啟動時重新啟動工作。

WorkerFactory:一個默認(rèn)工廠,用于創(chuàng)建 Worker 的實(shí)例。我們將在以后的博文中介紹為什么以及如何配置它。

Default Executor:一個默認(rèn)的執(zhí)行程序,運(yùn)行你的工作,除非你另行指定。這確保在默認(rèn)情況下,你的工作是同步運(yùn)行的,并且在主線程之外運(yùn)行。

這些部分可以被重寫以具有不同的行為。

來自:Working with WorkManager Android 開發(fā)者大會展示 2018

當(dāng)你安排 WorkRequest

    內(nèi)部 TaskExecutor 立即將你的 WorkRequest 信息保存到 WorkManager 數(shù)據(jù)庫。

    稍后,當(dāng)滿足 WorkRequestConstraints 時(可以立即發(fā)生),Internal TaskExecutor 會告訴 WorkerFactory 創(chuàng)建一個 Worker

    之后,默認(rèn)的 Executor 調(diào)用你的 WorkerdoWork() 方法脫離主線程。

通過這種方式,默認(rèn)情況下,你的工作都可以保證執(zhí)行脫離主線程運(yùn)行。

現(xiàn)在,如果你想使用除默認(rèn) Executor 之外的一些其他機(jī)制來運(yùn)行你的工作,也是可以的!對協(xié)程(CoroutineWorker)和 RxJava(RxWorker)的開箱即用支持作為工作的手段。

或者,你可以使用 ListenableWorker 準(zhǔn)確指定工作的執(zhí)行方式。Worker 實(shí)際上是 ListenableWorker 的一個實(shí)現(xiàn),它默認(rèn)在默認(rèn)的 Executor 上運(yùn)行你的工作,因此是同步的。所以,如果你想要完全控制工作的線程策略或異步運(yùn)行工作,你可以將 ListenableWorker 子類化(具體細(xì)節(jié)將在后面的文章中討論)。

WorkManager 雖然將所有工作信息保存到數(shù)據(jù)庫中有些麻煩,但它還是會做,這使得它成了非常適合需要保障執(zhí)行的任務(wù)。這也是使得 WorkManager 輕松應(yīng)對對于不需要保障且只需要在后臺線程上執(zhí)行的任務(wù)的的原因。例如,假設(shè)你已經(jīng)下載了圖像,并且希望根據(jù)該圖像更改 UI 部分的顏色。這是應(yīng)該脫離主線程運(yùn)行的工作,但是,因為它與 UI 直接相關(guān),所以如果關(guān)閉應(yīng)用程序則不需要繼續(xù)。所以在這樣的情況下,不要使用 WorkManager —— 堅持使用像 Kotlin 協(xié)程那樣輕量的東西或創(chuàng)建自己的 Executor。

使用鏈進(jìn)行依賴性工作

我們的濾鏡示例包含的不僅僅是一個任務(wù) —— 我們想要給多個圖像加濾鏡,然后壓縮并上傳。如果要一個接一個地或并行地運(yùn)行一系列 WorkRequests,則可以使用 鏈。示例圖顯示了一個鏈,其中有三個并行運(yùn)行的濾鏡任務(wù),后面是壓縮任務(wù)和上傳任務(wù),按順序運(yùn)行:

使用 WorkManager 非常簡單。假設(shè)你已經(jīng)用適當(dāng)?shù)募s束創(chuàng)建了所有 WorkRequests,代碼如下所示:

WorkManager.getInstance()
    .beginWith(Arrays.asList(
                             filterImageOneWorkRequest, 
                             filterImageTwoWorkRequest, 
                             filterImageThreeWorkRequest))
    .then(compressWorkRequest)
    .then(uploadWorkRequest)
    .enqueue()

三個圖片濾鏡 WorkRequests 并行執(zhí)行。一旦完成所有濾鏡 WorkRequests (并且只有完成所有三個),就會發(fā)生 compressWorkRequest,然后是 uploadWorkRequest

鏈的另一個優(yōu)點(diǎn)是:一個 WorkRequest 的輸出作為下一個 WorkRequest 的輸入。因此,假設(shè)你正確設(shè)置了輸入和輸出數(shù)據(jù),就像我上面的 UploadWorker 示例所做的那樣,這些值將自動傳遞。

為了處理并行的三個濾鏡工作請求的輸出,可以使用 InputMerger,特別是 ArrayCreatingInputMerger。代碼如下:

val compressWorkRequest = OneTimeWorkRequestBuilder()
        .setInputMerger(ArrayCreatingInputMerger::class.java)
        .setConstraints(constraints)
        .build()

請注意,InputMerger 是添加到 compressWorkRequest 中的,而不是并行的三個濾鏡請求中的。

假設(shè)每個濾鏡工作請求的輸出是映射到圖像 URI 的鍵 “KEY_IMAGE_URI”。添加 ArrayCreatingInputMerger 的作用是并行請求的輸出,當(dāng)這些輸出具有匹配的時,它會創(chuàng)建一個包含所有輸出值的數(shù)組,映射到單個鍵??梢暬瘓D表如下:

ArrayCreatingInputMerger 功能可視化

因此,compressWorkRequest 的輸入將最終成為映射到濾鏡圖像 URI 數(shù)組的 “KEY_IMAGE_URI” 對。

觀察你的 WorkRequest 狀態(tài)

監(jiān)視工作的最簡單方法是使用 LiveData 類。如果你不熟悉 LiveData,它是一個生命周期感知的可監(jiān)視數(shù)據(jù)持有者 —— 這里 對此有更詳細(xì)的描述。

調(diào)用 getWorkInfoByIdLiveData 返回一個 WorkInfoLiveDataWorkInfo 包含輸出的數(shù)據(jù)和表示工作狀態(tài)的枚舉。當(dāng)工作順利完成后,它的 State 就會是 SUCCEEDED。因此,例如,你可以通過編寫一些監(jiān)視代碼來實(shí)現(xiàn)當(dāng)工作完成時自動顯示該圖像:

// In your UI (activity, fragment, etc)
WorkManager.getInstance().getWorkInfoByIdLiveData(uploadWorkRequest.id)
        .observe(lifecycleOwner, Observer { workInfo ->
            // Check if the current works state is "successfully finished"
            if (workInfo != null && workInfo.state == WorkInfo.State.SUCCEEDED) {
                displayImage(workInfo.outputData.getString(KEY_IMAGE_URI))
            }
        })

有幾點(diǎn)需要注意:

每個 WorkRequest 都有一個唯一的 id,該唯一 id 是查找關(guān)聯(lián) WorkInfo 的一種方法。

WorkInfo 更改時進(jìn)行監(jiān)視并被通知的能力是 LiveData 提供的功能。

工作有一個由不同 State 代表的生命周期。監(jiān)視 LiveData 時,你會看到這些狀態(tài);例如,你可能會看到:

“happy path” 或工作狀態(tài)

工作狀態(tài)經(jīng)歷的 “happy path” 如下:

    BLOCKED:只有當(dāng)工作在鏈中并且不是鏈中的下一個工作時才會出現(xiàn)這種狀態(tài)。

    ENQUEUED:只要工作是工作鏈中的下一個并且有資格運(yùn)行,工作就會進(jìn)入這個狀態(tài)。這項工作可能仍在等待 Constraint 被滿足。

    RUNNING:在這種狀態(tài)時,工作正在運(yùn)行。對于 Worker,這意味著 doWork() 方法已經(jīng)被調(diào)用。

    SUCCEEDED:當(dāng) doWork() 返回 Result.success() 時,工作進(jìn)入這種最終狀態(tài)。

現(xiàn)在,當(dāng)工作處于 RUNNING 狀態(tài),你可以調(diào)用 Result.retry()。這將會導(dǎo)致工作退回 ENQUEUED 狀態(tài)。工作也可能隨時被 CANCELLED。

如果工作運(yùn)行的結(jié)果是 Result.failure() 而不是成功。它的狀態(tài)將會以 FAILED 結(jié)束,因此,狀態(tài)的完整流程圖如下所示:

(來自:Working with WorkManager Android 開發(fā)者峰會 2018)

想看精彩的視頻講解,請查看 WorkManager Android 開發(fā)者峰會演講。

總結(jié)

這就是 WorkManager API 的基礎(chǔ)知識。使用我們剛剛介紹的代碼片段,你現(xiàn)在就可以:

創(chuàng)建包含輸入/輸出的 Worker。

使用 WorkRequestConstraint、啟動輸入和退出策略配置 Worker 的運(yùn)行方式。

調(diào)度 WorkRequest。

了解默認(rèn)情況下 WorkManager 在線程和保障運(yùn)行方面的幕后工作。

創(chuàng)建復(fù)雜鏈?zhǔn)较嗷ヒ蕾嚨墓ぷ?,可以順序運(yùn)行和并行運(yùn)行。

使用 WorkInfo 監(jiān)視你的 WorkRequest 的狀態(tài)。

想親自試試 WorkManager 嗎?查看 codelab,包含 Kotlin 和 Java 代碼。

隨著我們繼續(xù)更新本系列,請繼續(xù)關(guān)注有關(guān) WorkManager 主題的更多博客文章。 有什么問題或者你希望我們寫到的東西嗎?請在評論區(qū)告訴我們!

感謝 Pietro Maggi

WorkManager 相關(guān)資源

官方文檔

參考指南

WorkManager 1.0.0-beta02 Release notes

Codelab:Kotlin 和 Java.

源碼(AOSP 的一部分)

Working with WorkManager (Android 開發(fā)者峰會 2018) presentation

Issue Tracker

StackOverflow 上面的 WorkManager 相關(guān)問題

Google’s Power blog post series

如果發(fā)現(xiàn)譯文存在錯誤或其他需要改進(jìn)的地方,歡迎到 掘金翻譯計劃 對譯文進(jìn)行修改并 PR,也可獲得相應(yīng)獎勵積分。文章開頭的 本文永久鏈接 即為本文在 GitHub 上的 MarkDown 鏈接。


掘金翻譯計劃 是一個翻譯優(yōu)質(zhì)互聯(lián)網(wǎng)技術(shù)文章的社區(qū),文章來源為 掘金 上的英文分享文章。內(nèi)容覆蓋 Android、iOS、前端、后端、區(qū)塊鏈、產(chǎn)品、設(shè)計、人工智能等領(lǐng)域,想要查看更多優(yōu)質(zhì)譯文請持續(xù)關(guān)注 掘金翻譯計劃、官方微博、知乎專欄。

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/7044.html

相關(guān)文章

  • WorkManager入門到實(shí)踐,有這一篇就夠了

    摘要:前言上一次我們對的應(yīng)用進(jìn)行了一次全面的分析,這一次我們來聊聊。 showImg(https://segmentfault.com/img/remote/1460000020077803?w=1280&h=853); 前言 上一次我們對Paging的應(yīng)用進(jìn)行了一次全面的分析,這一次我們來聊聊WorkManager。 如果你對Paging還未了解,推薦閱讀這篇文章: Paging在Recy...

    bingchen 評論0 收藏0
  • [] 在 Android 使用協(xié)程(part III) - 在實(shí)際工作中使用

    摘要:通過實(shí)現(xiàn)一次請求來解釋使用協(xié)程中的實(shí)際問題是這篇文章的重點(diǎn)。當(dāng)接收一個新事件時,啟動一個新的協(xié)程來對列表進(jìn)行排序,并在響應(yīng)時更新。在中啟動協(xié)程作為一般模式。因此,在默認(rèn)情況下,在存儲庫中啟動的任何協(xié)程都會泄露。 原文鏈接:Coroutines On Android (part III): Real work 原文作者:Sean McQuillan 這是一篇關(guān)于在 Android 上使用...

    番茄西紅柿 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<