経緯
プロダクトで定期的に実行する機能の開発があり、Workerというものを採用することになりました
その際にいくつか詰まったところがあったので、使い方や使用感をまとめたいと思います
Workerとは
困ったところ
WorkerはWorkManagerというAndroidフレームワークによって生成されます
その際にコンストラクタで受け取れる引数はContextとWorkerParametersのみで、他のオブジェクトを受け取ることはできません
それを実現するためには、独自のWorkerFactoryを作り、WorkManagerに渡してあげる必要があります
手順
- Workerを作成する
今回は独自のLogユースケースクラスを引数に取るWorkerを作ります
class LogWorker( context: Context, params: WorkerParameters, private val logUseCase: LogUseCase ) : Worker(context, params) { override fun doWork(): Result { logUseCase.start() return Result.success() } }
- WorkerFactoryを継承したLogFactoryを作成
class LogWorkerFactory( private val logUseCase: LogUseCase ) : WorkerFactory() { override fun createWorker( appContext: Context, workerClassName: String, workerParameters: WorkerParameters ): ListenableWorker? { return if (workerClassName == LogWorker::class.java.name){ LogWorker(appContext, workerParameters, logUseCase) } else { null } } }
- 作成したLogWorkerFactoryを呼び出したいクラスからWorkManager.initialize()メソッド経由でWorkerManagerへ登録
class MyApplication : Application() { override fun onCreate() { super.onCreate() WorkManager.initialize( this, Configuration.Builder().setWorkerFactory(LogWorkerFactory()) .build() ) } }
- デフォルトのWorkManagerInitializerを削除する旨をマニフェストファイルに記載
<manifest ...> <application ...> ... <provider android:name="androidx.work.impl.WorkManagerInitializer" android:authorities="${applicationId}.workmanager-init" tools:ignore="ExportedContentProvider" tools:node="remove" /> </application> </manifest>
- 通常通り呼び出しを行う()
今回は定期実行ということでPeriodicWorkRequestクラスを利用します
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val workManager = WorkManager.getInstance() val logPeriodicWorkRequest = PeriodicWorkRequest.Builder( LogWorker::class.java, Duration.ofMinutes(15) ).build() val operation = workerManager.enqueue(logPeriodicWorkRequest) workManager.enqueue(OneTimeWorkRequest.from(LogWorker::class.java)) } }
通常はここで終わりなんですが、プロダクトではDaggerを使っているので、provide メソッドによる管理を行いたいと思います
WorkerをDIしようとすると結構な手順が必要になるので、今回はWorkerではなく、WorkerFactoryのみDIしたいと思います
WorkerごとDIしたい場合は下記を参照
手順は簡単です
- provideメソッドをモジュールにセット
@Provides @Singleton fun provideWorkerFactory( logUseCase: LogUseCase ): WorkerFactory { return LogFactory(logUseCase) }
- 呼び出しもとでInjectする
class MainActivity : AppCompatActivity() { @Inject lateinit var workerFactory: WorkerFactory override fun onCreate(savedInstanceState: Bundle?) { (省略) } }
まとめ
今回はDagger環境でWorkerを使う方法について解説しました
定期実行したいという際にまず出てくるのがWorkerという選択肢だと思うので、今後も使う機会があるのではないでしょうか
今回参考にさせていただいたページは下記です
今回も最後まで読んでいただいてありがとうございました
https://proandroiddev.com/dagger-2-setup-with-workmanager-a-complete-step-by-step-guild-bb9f474bde37