Search code examples
androidkotlin-coroutinesandroid-workmanagerdagger-hilt

how to make an API request inside workManager?


I'm trying to use WorkManager for a periodic to retrieve notifications count from the API, the problem is that I'm using hilt for the dependency injection therefore I can't inject my repository with "@Inject" even if i used @AndroidEnteryPoint. And how I can observe my retrieved data inside the "doWork" function.

    class NotificationsCountWorker
    (
    val context: Context,
    workerParams: WorkerParameters) :
    CoroutineWorker(context, workerParams) {


    @Inject lateinit var repo: RepositoryImpl
   
    
    override suspend fun doWork(): Result {
        Log.d(TAG, "doWork")
        //subscribeObserver()
        return try {
            withContext(Dispatchers.IO) {
                try {
                    Log.d(TAG, "inside with context")
                    repo.notificationsCount().onEach {
                        Log.d(TAG, "item; $it")
                    }.launchIn(this)
                    Log.d(TAG, "notif count ")
                    Result.success()

                } catch (e: Exception){
                    Log.d(TAG, "exception ${e.message}")
                    Result.failure()
                }
            }
        }catch (e:Exception){
            Log.d(TAG, "exception ${e.message}")
            Result.failure()
        }


}


    companion object {
    private const val TAG = "NotificationsWorkManger"
    const val NOTIFICATIONS_COUNT_WORK_MANGER_ID = "automatic_notifications_count_manger"
    fun reminder() {
        val periodicRefreshRequest = PeriodicWorkRequest.Builder(
            NotificationsCountWorker::class.java, // Your worker class
            15, // repeating interval
            TimeUnit.MINUTES
        )

        val periodicWorkRequest: PeriodicWorkRequest = periodicRefreshRequest
            .build()
        WorkManager.getInstance(getApplication()).enqueueUniquePeriodicWork(
            NOTIFICATIONS_COUNT_WORK_MANGER_ID,
            ExistingPeriodicWorkPolicy.REPLACE,
            periodicWorkRequest
        )
    }
}


}

Solution

  • You need to inject your dependencies through a constructor. In order to enable injection to a Worker with Hilt you need to do the following.

    First, annotate your Worker, its constructor and constructor arguments as such:

    @HiltWorker
    class MyWorker @AssistedInject constructor(
        @Assisted context: Context,
        @Assisted workerParameters: WorkerParameters,
        private val repository: Repository
    ) : CoroutineWorker(context, workerParameters)
    

    You should only annotate context and workerParameters as @Assisted. All your other dependencies are resolved by Hilt, they must be installed in SingletonComponent or be unscoped.

    Then inject HiltWorkerFactory to your main Application-derived class and make this class implement the Configuration.Provider interface like this:

    @HiltAndroidApp
    class MainApplication : Application(), Configuration.Provider {
    
        @Inject
        lateinit var workerFactory: HiltWorkerFactory
    
        override fun getWorkManagerConfiguration() =
            Configuration.Builder()
                .setWorkerFactory(workerFactory)
                .build()
    }
    

    The final step is to disable default WorkManager initialization. To do this, insert these lines to your AndroidManifest.xml if you're using WorkManager of version 2.6.0-alpha01 or higher:

    <provider
        android:name="androidx.startup.InitializationProvider"
        android:authorities=\"${applicationId}.androidx-startup"
        android:exported="false"
        tools:node=\"merge">
        <!-- If you are using androidx.startup to initialize other components -->
        <meta-data
            android:name="androidx.work.impl.WorkManagerInitializer"
            android:value="androidx.startup"
            tools:node="remove" />
    </provider>
    

    or

    <!-- If you want to disable android.startup completely. -->
    <provider
        android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.androidx-startup"
        tools:node="remove">
    </provider>
    

    If you're using older versions, you should add this:

    <provider
        android:name="androidx.work.impl.WorkManagerInitializer"
        android:authorities="${applicationId}.workmanager-init"
        tools:node="remove" />