使用 Dagger 自定義 WorkManager

2021-03-02 谷歌開發者
WorkManager 是一個 Android Jetpack 擴展庫,它可以讓您輕鬆規劃那些可延後、異步但又需要可靠運行的任務。對於絕大部分後臺執行任務來說,使用 WorkManager 是目前 Android 平臺上的最佳實踐。https://developer.android.google.cn/topic/libraries/architecture/workmanager/https://developer.android.google.cn/jetpack/如果您一直關注本系列文章,則會發現我們已經討論過:

在本篇文章中,我們將會討論使用 Dagger 自定義配置相關的內容,包括:

在我們的 WorkerFactory 中使用 Dagger 注入參數⚠️  本文擴展自上一篇自定義 WorkManager 的文章。強烈建議在閱讀本文之前先去閱讀上一篇文章!

為什麼是 Dagger

https://developer.android.google.cn/training/dependency-injection/dagger-basicshttps://codelabs.developers.google.com/codelabs/android-dagger/index.html行文中我假設您對 Dagger 庫和依賴注入概念均已有所了解。即使您正在使用其他的依賴注入庫,或者根本沒有使用依賴庫,本文所呈現的概念依然會對您有所幫助。上一篇文章中,我們探索了如何自定義 WorkManager,其中包括如何使用 DelegatingWorkerFactory 將附加的參數傳遞到 Worker 中。在本篇文章中,讓我們看一看如何使用 Dagger 注入這些參數。

使用 Dagger 將參數注入到 WorkerFactory

如果您當前已經在使用 Dagger 來管理依賴,那麼首先需要將 Dagger 集成到您的 WorkerFactory 中。如果您使用 Dagger 在您的應用中傳遞 Retrofit 服務的引用,而且您想要將其傳遞給您的 Worker,則需要使用 Dagger 將該引用注入到自定義的 WorkerFactory 中。這樣一來,WorkFactory 就可以使用 Retrofit 的引用作為額外參數來初始化您的 Worker。假設這次我們有了 Dagger 注入的 Retrofit 服務的引用。但是這並沒有改變 WorkManager 需要自定義工廠和自定義配置的局面。簡單來說,我們將用 Dagger 把新的參數注入到我們的工廠中。
@Singletonclass MyWorkerFactory @Inject constructor(    service: DesignerNewsService) : DelegatingWorkerFactory() {    init {        addFactory(myWorkerFactory(service))     }} 

提示: 如果想要 Dagger 能夠注入這個值,我們必須把它放進 Dagger 的圖中。這就是為什麼我們給 Factory 添加了一個 @inject 註解。本示例中,我們在 Application 裡使用一個 AppComponent 來設置 Dagger。AppComponent 稍後會在 MyApplication 中初始化,從而讓 Dagger 可以進行成員注入:
@Singleton@Component(modules = [AppModule::class])interface AppComponent {
@Component.Factory interface Factory { fun create(@BindsInstance context: Context): AppComponent }
fun inject(application: MyApplication)}

隨後,我們在 Application 類中注入我們的組件:
class MyApplication : Application(), Configuration.Provider {    
lateinit var appComponent: AppComponent
override fun onCreate() { super.onCreate() appComponent = DaggerAppComponent.factory().create(applicationContext) appComponent.inject(this) } ...}

由於 Dagger 已經知道如何提供 MyWorkerFactory 實例,您現在可以通過使用 @Inject 來從 Dagger 圖中獲取 MyWorkerFactory,並在 getWorkManagerConfiguration 方法中進行使用。

class MyApplication : Application(), Configuration.Provider {
@Inject lateinit var myWorkerFactory: MyWorkerFactory ...
override fun getWorkManagerConfiguration(): Configuration = Configuration.Builder() .setMinimumLoggingLevel(android.util.Log.INFO) .setWorkerFactory(myWorkerFactory) .build() ...}

在使用中型或大型資料庫時,Dagger 的表現十分亮眼。我們升級了 Google I/O 與 Android 開發峰會的時間表應用: iosched,使其用上 WorkManager 和 Dagger,它同時也是我們用於展示協程 Flow 最佳實踐的應用,詳情請查看文章: 基於 Android 開發者峰會應用的協程 Flow 最佳實踐。在 2019 Android 開發者峰會應用中,JobScheduler 被 WorkManager 所取代,用於強制更新時間表。為了能將時間表的緊急更新強制推送至設備,我們為應用添加了這個功能。在這種情況下,我們需要在 Worker 中使用的額外參數是 refreshEventDataUseCase。您可以在 github 的 iosched 倉庫中的 ADSsched 分支中查看引入了此功能的提交 (commits)。讓我們從 Worker 本身開始,看看最重要的幾部分:

ConferenceDataWorker.kt

class ConferenceDataWorker(    ctx: Context,    params: WorkerParameters,    private val refreshEventDataUseCase: RefreshConferenceDataUseCase) : CoroutineWorker(ctx, params) {
override suspend fun doWork(): Result {
Timber.i("ConferenceDataService triggering refresh conference data.")
return try { refreshEventDataUseCase(Unit)            Timber.d("ConferenceDataService finished successfully.") Result.success() } catch (e: Exception) {            Timber.e("ConferenceDataService failed. It will retry.") if (runAttemptCount < MAX_NUMBER_OF_RETRY) { Result.retry() } else { Result.failure() } } }}

源碼: ConferenceDataWorker.kt

如您所見,由於在 WorkerFactory 級別處理了參數的傳遞,因此在 Worker 類上沒有 Dagger 註解。這個參數是 Dagger 已知的,因此可以將其直接注入到我們的自定義 WorkerFactory 中:
class ConferenceDataWorkerFactory(    private val refreshEventDataUseCase: RefreshConferenceDataUseCase) : WorkerFactory() {
override fun createWorker( appContext: Context, workerClassName: String, workerParameters: WorkerParameters ): ListenableWorker? {
return when (workerClassName) { ConferenceDataWorker::class.java.name -> ConferenceDataWorker(appContext, workerParameters, refreshEventDataUseCase)            else -> null } }}

源碼: ConferenceDataWorkerFactory.kt

源碼: ConferenceDataWorkerFactory.kthttps://github.com/google/iosched/blob/f237889eb568e501add09ca0728af9760ea7a193/shared/src/main/java/com/google/samples/apps/iosched/shared/data/work/ConferenceDataWorkerFactory.kt#L25這裡仍然沒有 Dagger 註解. 原因是我們使用了一個 DelegatingWorkerFactory 來協調那些單個的工廠 (此時,我們在 IOsched 中只有一個工廠,但是我們以一種在需要時可以直接添加更多工廠的方式來構建它):
@Singletonclass IoschedWorkerFactory @Inject constructor(    refreshConferenceDataUseCase: RefreshConferenceDataUseCase) : DelegatingWorkerFactory() {    init {        addFactory(ConferenceDataWorkerFactory(refreshConferenceDataUseCase))    }}

源碼: IoschedWorkerFactory.kt

IoschedWorkerFactory.kt

https://github.com/google/iosched/blob/adssched/shared/src/main/java/com/google/samples/apps/iosched/shared/data/work/IoschedWorkerFactory.kt

源碼: IoschedWorkerFactory.kt

https://github.com/google/iosched/blob/f237889eb568e501add09ca0728af9760ea7a193/shared/src/main/java/com/google/samples/apps/iosched/shared/data/work/IoschedWorkerFactory.kt#L24

OK,這裡就是使用 Dagger 向我們的構造函數注入參數的地方。在這個應用中,我們決定使用按需初始化,並且使用 Dagger 注入所有配置:
@Inject lateinit var workerConfiguration: Configuration
override fun getWorkManagerConfiguration(): Configuration { return workerConfiguration}

源碼: MainApplication.kt

https://github.com/google/iosched/blob/f237889eb568e501add09ca0728af9760ea7a193/mobile/src/main/java/com/google/samples/apps/iosched/MainApplication.kt#L38這使我們可以為不同的構建類型注入不同的配置。尤其是,我們為調試構建注入了日誌級別設置為 DEBUG 的配置:
@Singleton@Providesfun provideWorkManagerConfiguration(    ioschedWorkerFactory: IoschedWorkerFactory): Configuration {    return Configuration.Builder()        .setMinimumLoggingLevel(android.util.Log.DEBUG)        .setWorkerFactory(ioschedWorkerFactory)        .build()}

源碼: debugRelease SharedModule.kt

源碼: debugRelease SharedModule.kt

https://github.com/google/iosched/blob/f237889eb568e501add09ca0728af9760ea7a193/shared/src/debugRelease/java/com/google/samples/apps/iosched/shared/di/SharedModule.kt#L184

SharedModule.kt (在 shared/src/staging/j/c/g/s/a/i/shared/di/ 中)
@Singleton@Providesfun provideWorkManagerConfiguration(    ioschedWorkerFactory: IoschedWorkerFactory): Configuration {    return Configuration.Builder()        .setWorkerFactory(ioschedWorkerFactory)        .build()}

源碼: staging SharedModule.kt

https://github.com/google/iosched/blob/adssched/shared/src/staging/java/com/google/samples/apps/iosched/shared/di/SharedModule.kthttps://github.com/google/iosched/blob/f237889eb568e501add09ca0728af9760ea7a193/shared/src/staging/java/com/google/samples/apps/iosched/shared/di/SharedModule.kt#L135當我們首次獲取 WorkManager 實例時,WorkManager 將按需初始化。當我們收到 Firebase 消息以獲取新的時間表時,就會觸發這個操作:IoschedFirebaseMessagingService.kt
private fun scheduleFetchEventData() {    val constraints = Constraints.Builder()        .setRequiredNetworkType(NetworkType.CONNECTED)        .build()
val conferenceDataWorker = OneTimeWorkRequestBuilder<ConferenceDataWorker>() .setInitialDelay(MINIMUM_LATENCY, TimeUnit.SECONDS) .setConstraints(constraints) .build()
val operation = WorkManager.getInstance(this) .enqueueUniqueWork( uniqueConferenceDataWorker, ExistingWorkPolicy.KEEP, conferenceDataWorker) .result
operation.addListener( { Timber.i("ConferenceDataWorker enqueued..") }, { it.run() } )}

源碼: IoschedFirebaseMessagingService.kt

IoschedFirebaseMessagingService.kthttps://github.com/google/iosched/blob/adssched/shared/src/main/java/com/google/samples/apps/iosched/shared/fcm/IoschedFirebaseMessagingService.kt源碼: IoschedFirebaseMessagingService.kthttps://github.com/google/iosched/blob/f237889eb568e501add09ca0728af9760ea7a193/shared/src/main/java/com/google/samples/apps/iosched/shared/fcm/IoschedFirebaseMessagingService.kt#L51

至此,我們結束了探索如何使用 Dagger 把參數注入到您的 Worker,同時也了解了如何將 WorkManager 集成到 iosched 這類的大型應用中。

WorkManager 是一個功能十分強大的庫,它的默認配置已經可以覆蓋許多常見的使用場景。然而當您遇到某些情況時,諸如需要增加日誌級別或需要把額外參數傳入到您的 Worker 時,則需要一個自定義的配置。希望通過最近兩篇文章所做的介紹,能讓您對自定義 WorkManager 有一個良好的認識。如果您有任何疑問,可以在評論區中留言。 點擊屏末  | 查看 Android 官方中文文檔 —— 使用 WorkManager 調度任務

相關焦點

  • 自定義 WorkManager —— 基礎概念
    https://developer.android.google.cn/topic/libraries/architecture/workmanager/https://developer.android.google.cn/jetpack/目前為止本系列已經討論過:在本篇文章中,我們將會討論自定義配置相關的內容,包括:本系列的下一篇文章將對依賴注入和 Dagger 展開討論
  • Dagger2 神器入門(一)
    對於剛剛入門Dagger的同學們來講,這樣的文章只會讓你覺得生無可戀,看完之後還是不知道怎麼使用?對於新的知識,我們首先要知道的是它是做什麼的?能達到什麼效果?然後自己寫一個demo去玩玩,待你能夠簡單使用之後再去看看這些文章,這樣對自己的信心能很大提高。而不是一上來就看一大堆的註解和註解相關的內容,這樣繞著繞著,就把自己繞暈了。
  • Android 依賴注入框架 Dagger 2.1 詳解
    難道dagger更新了?本著落後就要挨打的原則去google了一番,發現國內資料通篇都是dagger原本的用法,並沒有找到我需要的。最後終於在國外網站找到了一篇dagger2.1新用法的介紹,配合dagger官網終於了解了一二,這也堅定了我從頭寫一篇Dagger文章的決心。
  • Cloak and dagger?
    Reader question:Please explain 「cloak and dagger」, as in 「a cloak and dagger film set in the 1920s」.wielding a dagger, a stabbing knife with a pointed blade.
  • 在Lightning Aura組件中使用自定義標籤
    要訪問Aura組件中的自定義標籤,請使用 $Label global value provider。在這篇文章中,我們將看到如何在閃電光環組件中使用自定義標籤。創建自定義標籤轉到設置-創建-自定義標籤。單擊新的自定義標籤。輸入值作為名稱,值和描述。
  • 使用vlookup解決自定義排序的問題,原來自定義排序竟如此簡單
    Hello,大家好,今天跟大家分享下如何自定義排序,實現想怎麼排序就怎麼排序,工作中我們可能會遇到這樣的問題,就是要根據給定的數據位置進行排序,如果我們直接使用排序excel會根據默認的排序規則進行排序,而不能達到我們想要的結果,解決這樣的問題,跟大家分享2種方法,一種是使用自定義排序
  • Scorpion Dagger:天才在左瘋子在右。
    自  嗨  音  樂  節  限  速  車  道   ——Scorpion Dagger 當你還想問點問題時 對方已轉身離開   如果還想了解關於Scorpion Dagger更多  請點擊進入藝術家官網  scorpiondagger.tumblr.com  圖片來自:scorpiondagger.tumblr.com
  • 百度輸入法如何使用自定義短語
    百度輸入法是著名搜尋引擎服務提供商百度公司免費提供的輸入軟體。它基於百度搜索技術,擁有強大的詞庫。  拼音輸入法  百度拼音輸入法最大的特點是無需下載客戶端,在線即可使用,它運用的是雲計算技術,用戶在電腦前輸入拼音後,數據傳輸到後臺的計算機處理中心,對應的漢字或詞語甚至句子將通過網際網路幾乎實時的顯現出來,由於雲計算後臺的處理能力比用戶使用的電腦強大很多倍,所以這種模式的輸入法準確率比較高。
  • 使用Gradle編譯Java工程之自定義Plugins篇
    我們可以自定義實現自己的Gradle插件,然後分享給其他人使用。我們可以使用不同的語言來實現,不過本章中作者選擇使用Groovy來實現的,大家也可以使用像java、scala等喜歡的別的語言來實現。Gradle自定義插件的實現和自定義任務類型非常的相似,而它兩一般都是結合使用的。
  • 輕鬆學Pytorch-自定義數據集製作與使用
    本文以人臉Landmard五點的數據集標定與之製作為例來說明pytorch中如何實現自定義數據集讀取與加載。首先要實現人臉landmark五點的數據標定,就得找到人臉數據,我使用的人臉數據是celebA數據集,大概有20W張多點,我從中選擇了1000張,然後通過OpenCV寫了個程序對人臉進行了簡單的裁剪。
  • macOS Big Sur:使用Control Center自定義菜單欄
    閱讀有關如何在macOS Big Sur中使用Control Center自定義菜單欄的信息。隨著首次更新的通知中心和控制中心的到來,默認情況下,macOS Big Sur的菜單欄比以往任何時候都最小。
  • 使用snapseed自定義樣式,快速修改照片
    今天我們就來討論自己個性化定義自己的樣式,來快速修改自己的圖片。點開工具我們可以看到snaoseed功能非常強大,遺憾的是沒有類似HSL顏色調整的功能。今天我們不討論工具的使用。一頓操作猛如虎,我調了一個自己想要的效果這時候我們打開樣式,往右劃到最後我們可以看到有個加號,就是它了。
  • 如何使用VBA編程進行自定義排序?
    第2種方法是字典+數組,藉助輔助列進行排序。優點是不會破壞單元格的各種屬性,比如公式、填充色、數據驗證等,缺點是畢竟用了輔助列,空間處理上需要注意下。第3種方法還是字典+數組,藉助計數排序的技巧,直接對數據在數組中進行排序。優點是效率較高,缺點是會破壞單元格除了值以外的屬性,比如刪除了公式、背景填充色等。
  • 創造與魔法自定義鍵位怎麼設置?自定義按鍵功能使用方法[視頻][多圖]
    創造與魔法自定義鍵位終於可以設置了,即將推出新的功能玩法,自動以按鍵上線後玩家們可以自由調整設置,喜歡什麼樣的按鍵設置就怎麼設置,根據個人的習慣和操作手法來設置按鍵,自定義按鍵功能的使用方法下面會有具體介紹。
  • 使用自定義格式打勾打叉
    Excel 自定義格式代碼,做起來效果挺好,講起來比較枯燥。所以就直接用一些常用的例子。今天介紹如何在Excel中打勾打叉。選擇區域,CTRL+1,自定義格式按如下設置。還可以自定義顏色。[綠色][=1]"√";[紅色][=0]"×"輸入1,顯示綠色的√,輸入0顯示紅色的×。注意,此種方法輸入的,最終保存的只是1或0。
  • excel自定義格式使用技巧一巧顯示單位
    解決方法:可以通過自定義來設置數據類型1.    使用組合鍵【CTRL+1】調用【設置單元格格式】窗口,如圖:3.    在調用的窗口中單擊【自定義】如圖:4.
  • 掌握學習CoreIDraw的插入按鈕條形碼自定義符號等工具的使用
    一、插入按鈕編輯菜單/插入網際網路對象,可以插入些網際網路中經常使用的網絡按鈕。三、自定義符號(圖形)可以將繪製好的圖形對象定義為符號,以方便下次直接使用。1.創建自定義符號:選擇繪製好的對象,單擊「編輯」菜單下的「符號」/「新建符號」,輸入符號名稱,單擊確定完成定義。2. 插入定義符號:單擊「編輯」菜單下的「符號」/「符號管理器」,在窗口右面彈出的泊塢窗中將會顯示出定義的圖形對象,單擊泊塢窗下方的「插入符號」就可在文檔中插入指定的符號。
  • 使用GrooveTube自定義YouTube應用的本機暗模式配色方案
    近期涉及使用GrooveTube自定義YouTube應用的本機暗模式配色方案內容備受矚目,很多讀者對此也很有興趣,現在給大家羅列關於使用GrooveTube自定義YouTube應用的本機暗模式配色方案最新消息。
  • pytorch編程之使用自定義 C ++類擴展 TorchScript
    注意,無論何時使用自定義類的實例,我們都通過c10::intrusive_ptr&lt;&gt;的實例來實現。將intrusive_ptr視為類似於std::shared_ptr的智能指針。使用此智能指針的原因是為了確保在語言(C ++,Python 和 TorchScript)之間對對象實例進行一致的生命周期管理。
  • VBA自定義函數
    '1 什麼是自定義函數? '在VBA中有VBA函數,我們還可以調用工作表函數,我們能不能自已編寫函數呢?