2020年7月16日木曜日

WorkerFactory を使って WorkManager の Worker を生成する

WorkerFactory を使うので Worker のコンストラクタでは任意の引数を取れる。
  1. class MyWorker(  
  2.     context: Context,  
  3.     params: WorkerParameters,  
  4.     private val api: MyApi,  
  5.     private val dataStore: DataStore  
  6. ) : CoroutineWorker(context, params) {  
  7.   
  8.     override suspend fun doWork(): Result {  
  9.         return try {  
  10.             val data = api.getData()  
  11.             dataStore.save(data)  
  12.             Result.success()  
  13.         } catch (e: Exception) {  
  14.             Timber.e(e)  
  15.             Result.failure()  
  16.         }  
  17.     }  
  18. }  
WorkerFactory を用意する。
  1. class MyWorkerFactory(  
  2.     private val api: MyApi,  
  3.     private val dataStore: DataStore  
  4. ) : WorkerFactory() {  
  5.   
  6.     override fun createWorker(  
  7.         appContext: Context,  
  8.         workerClassName: String,  
  9.         workerParameters: WorkerParameters  
  10.     ): ListenableWorker? {  
  11.         return if (workerClassName == MyWorker::class.java.name) {  
  12.             MyWorker(appContext, workerParameters, api, dataStore)  
  13.         } else {  
  14.             null  
  15.         }  
  16.     }  
  17. }  
default initializer を削除するための記述を AndroidManifest に追加する。
  1. <manifest ...>  
  2.   
  3.     <application  
  4.         ...>  
  5.   
  6.         ...  
  7.   
  8.         <provider  
  9.             android:name="androidx.work.impl.WorkManagerInitializer"  
  10.             android:authorities="${applicationId}.workmanager-init"  
  11.             tools:ignore="ExportedContentProvider"  
  12.             tools:node="remove" />  
  13.   
  14.     </application>  
  15.   
  16. </manifest>  
Application で Configuration.Provider を実装し、getWorkManagerConfiguration() で返す Configuration で MyWorkerFactory を指定する。
直接 MyWorkerFactory を setWorkerFactory() に渡してもいいが、DelegatingWorkerFactory を使うと複数の Factory から構成させる Factory を作ることができる。
  1. class MyApplication : Application(), Configuration.Provider {  
  2.   
  3.     ...  
  4.   
  5.     override fun getWorkManagerConfiguration(): Configuration {  
  6.         val api = appComponent.api()  
  7.         val dataStore = appComponent.dataStore()  
  8.   
  9.         val delegatingWorkerFactory = DelegatingWorkerFactory().apply {  
  10.             addFactory(MyWorkerFactory(api, dataStore))  
  11.         }  
  12.   
  13.         return Configuration.Builder()  
  14.             .setWorkerFactory(delegatingWorkerFactory)  
  15.             .build()  
  16.     }  
  17. }  
Subcomponent を使えば WorkerFactory と Worker 両方 Dagger に生成させることもできるし、なんなら Hilt には HiltWorkerFactory が用意されている。

参考

2020年7月14日火曜日

依存 module に無い buildType がある場合 matchingFallbacks を使う

proguard を有効にしたビルドで debuggable な処理をしたいとき、debug を引き継いで proguard を有効にした buildType (以下の minify) を追加したくなると思います。

app/build.gradle
  1. android {  
  2.     ...  
  3.     buildTypes {  
  4.         minify {  
  5.             initWith debug  
  6.             minifyEnabled true  
  7.             proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"  
  8.         }  
  9.         release {  
  10.             minifyEnabled true  
  11.             proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"  
  12.   
  13.             ...  
  14.         }  
  15.     }  
  16.   
  17.     ...  
  18.   
  19.     testBuildType "minify"  
  20. }  
  21.   
  22. dependencies {  
  23.     implementation project(":api")  
  24.   
  25.     ...  
  26. }  
依存している api モジュールに debug と release しか無い場合、このままだと Build Variants に minify を選んだときに gradle sync に失敗します。なぜなら api モジュールでは minify がないので debug と release のどちらを使えばいいかわからないからです。

api/build.gradle
  1. android {  
  2.     ...  
  3.   
  4.     buildTypes {  
  5.         release {  
  6.             minifyEnabled false  
  7.             proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"  
  8.         }  
  9.     }  
  10. }  
  11. ...  


これを解決するには matchingFallbacks を使います。依存モジュールに対応する buildType が無い場合、ここで指定した buildType が使われます。
ここでは debug を指定しているので、app で buildType に minify を選ぶと、api では buildType として debug が選択されます。

app/build.gradle
  1. android {  
  2.     ...  
  3.     buildTypes {  
  4.         minify {  
  5.             initWith debug  
  6.             minifyEnabled true  
  7.             proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"  
  8.   
  9.             matchingFallbacks = ['debug'// これを追加  
  10.         }  
  11.         release {  
  12.             minifyEnabled true  
  13.             proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"  
  14.   
  15.             ...  
  16.         }  
  17.     }  
  18.   
  19.     ...  
  20.   
  21.     testBuildType "minify"  
  22. }  
  23. ...  


参考