Clean Architecture, Clean Life

仕事・個人での技術的なことつぶやきます

【Android】WorkerFactoryをDaggerでDIする

経緯

プロダクトで定期的に実行する機能の開発があり、Workerというものを採用することになりました

その際にいくつか詰まったところがあったので、使い方や使用感をまとめたいと思います

Workerとは

困ったところ

WorkerはWorkManagerというAndroidフレームワークによって生成されます

その際にコンストラクタで受け取れる引数はContextとWorkerParametersのみで、他のオブジェクトを受け取ることはできません

それを実現するためには、独自のWorkerFactoryを作り、WorkManagerに渡してあげる必要があります

手順

  1. 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()
    }
}
  1. 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
        }
    }
}
  1. 作成したLogWorkerFactoryを呼び出したいクラスからWorkManager.initialize()メソッド経由でWorkerManagerへ登録
class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        WorkManager.initialize(
            this,
            Configuration.Builder().setWorkerFactory(LogWorkerFactory())
                .build()
        )
    }

}
  1. デフォルトのWorkManagerInitializerを削除する旨をマニフェストファイルに記載
<manifest ...>    
    <application  
        ...>  
  
        ...  
  
        <provider  
            android:name="androidx.work.impl.WorkManagerInitializer"  
            android:authorities="${applicationId}.workmanager-init"  
            tools:ignore="ExportedContentProvider"  
            tools:node="remove" />  
  
    </application>  
</manifest>  
  1. 通常通り呼び出しを行う()

今回は定期実行ということでPeriodicWorkRequestクラスを利用します

qiita.com

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したい場合は下記を参照

akihito104.hatenablog.com

qiita.com

tech.studyplus.co.jp

手順は簡単です

  1. provideメソッドをモジュールにセット
    @Provides
    @Singleton
    fun provideWorkerFactory(
        logUseCase: LogUseCase
    ): WorkerFactory {
        return LogFactory(logUseCase)
    }
  1. 呼び出しもとでInjectする
class MainActivity : AppCompatActivity() {

    @Inject
    lateinit var workerFactory: WorkerFactory

    override fun onCreate(savedInstanceState: Bundle?) {
        (省略)
    }
}

まとめ

今回はDagger環境でWorkerを使う方法について解説しました

定期実行したいという際にまず出てくるのがWorkerという選択肢だと思うので、今後も使う機会があるのではないでしょうか

今回参考にさせていただいたページは下記です

今回も最後まで読んでいただいてありがとうございました

y-anz-m.blogspot.com

www.webdevqa.jp.net

https://proandroiddev.com/dagger-2-setup-with-workmanager-a-complete-step-by-step-guild-bb9f474bde37