2020年7月16日木曜日

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

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

参考

2020年7月14日火曜日

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

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

app/build.gradle android { ... buildTypes { minify { initWith debug minifyEnabled true proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" } release { minifyEnabled true proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ... } } ... testBuildType "minify" } dependencies { implementation project(":api") ... } 依存している api モジュールに debug と release しか無い場合、このままだと Build Variants に minify を選んだときに gradle sync に失敗します。なぜなら api モジュールでは minify がないので debug と release のどちらを使えばいいかわからないからです。

api/build.gradle android { ... buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" } } } ...

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

app/build.gradle android { ... buildTypes { minify { initWith debug minifyEnabled true proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" matchingFallbacks = ['debug'] // これを追加 } release { minifyEnabled true proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ... } } ... testBuildType "minify" } ...

参考