From 524f2d529d1ab6af6c252f8926d4b2100dbf60a5 Mon Sep 17 00:00:00 2001 From: DS Date: Fri, 15 Jul 2022 23:22:35 +0530 Subject: [PATCH 1/2] Workers use @HiltWorker Assisted injection --- .../java/com/example/background/di/WorkManagerInitModule.kt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 WorkManagerSample/app/src/main/java/com/example/background/di/WorkManagerInitModule.kt diff --git a/WorkManagerSample/app/src/main/java/com/example/background/di/WorkManagerInitModule.kt b/WorkManagerSample/app/src/main/java/com/example/background/di/WorkManagerInitModule.kt new file mode 100644 index 00000000..bdbf51b4 --- /dev/null +++ b/WorkManagerSample/app/src/main/java/com/example/background/di/WorkManagerInitModule.kt @@ -0,0 +1,4 @@ +package com.example.background.di + +object WorkManagerInitModule { +} \ No newline at end of file From ff5b093adbb6ffb580cbbf37ba40406950613bd1 Mon Sep 17 00:00:00 2001 From: DS Date: Fri, 15 Jul 2022 23:31:27 +0530 Subject: [PATCH 2/2] Used App startup with Hilt to provide work-manager instance on demand Refactored the whole app to use Hilt for dependency injection, especially the worker classes. --- WorkManagerSample/app/build.gradle | 7 ++++ .../main/java/com/example/background/App.kt | 8 ++++- .../com/example/background/FilterActivity.kt | 4 ++- .../com/example/background/FilterViewModel.kt | 17 +++++----- .../example/background/SelectImageActivity.kt | 2 ++ .../background/di/WorkManagerInitModule.kt | 28 +++++++++++++++- WorkManagerSample/build.gradle | 1 + WorkManagerSample/lib/build.gradle | 6 ++++ .../background/workers/CleanupWorker.kt | 9 +++++- .../workers/SaveImageToGalleryWorker.kt | 16 ++++++++-- .../background/workers/UploadWorker.kt | 9 +++++- .../workers/filters/BaseFilterWorker.kt | 32 +++++++++++-------- .../workers/filters/BlurEffectFilterWorker.kt | 9 +++++- .../workers/filters/GrayScaleFilterWorker.kt | 9 +++++- .../workers/filters/WaterColorFilterWorker.kt | 9 +++++- WorkManagerSample/versions.gradle | 19 ++++++++++- 16 files changed, 152 insertions(+), 33 deletions(-) diff --git a/WorkManagerSample/app/build.gradle b/WorkManagerSample/app/build.gradle index c1ad6ab4..485e1dd2 100644 --- a/WorkManagerSample/app/build.gradle +++ b/WorkManagerSample/app/build.gradle @@ -16,6 +16,8 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' +apply plugin: 'dagger.hilt.android.plugin' android { compileSdkVersion build_versions.compile_sdk @@ -66,6 +68,11 @@ dependencies { implementation deps.retrofit.gson implementation deps.okhttp_logging_interceptor implementation deps.glide.runtime + implementation deps.hilt.dagger_hilt_android + kapt deps.hilt.hilt_compiler + implementation deps.hilt.hilt_work + kapt deps.hilt.androidx_hilt_compiler + implementation deps.app_startup testImplementation deps.junit androidTestImplementation deps.atsl.ext_junit diff --git a/WorkManagerSample/app/src/main/java/com/example/background/App.kt b/WorkManagerSample/app/src/main/java/com/example/background/App.kt index 2bd61c43..0e557428 100644 --- a/WorkManagerSample/app/src/main/java/com/example/background/App.kt +++ b/WorkManagerSample/app/src/main/java/com/example/background/App.kt @@ -18,19 +18,25 @@ package com.example.background import android.app.Application import android.util.Log +import androidx.hilt.work.HiltWorkerFactory import androidx.work.Configuration import androidx.work.WorkManager import com.example.background.workers.RenameWorkerFactory +import dagger.hilt.android.HiltAndroidApp import java.util.concurrent.Executors +import javax.inject.Inject /** * The [Application]. Responsible for initializing [WorkManager] in [Log.VERBOSE] mode. */ +@HiltAndroidApp class App : Application(), Configuration.Provider { + @Inject lateinit var workerFactory: HiltWorkerFactory + override fun getWorkManagerConfiguration() = Configuration.Builder() - .setWorkerFactory(RenameWorkerFactory()) + .setWorkerFactory(workerFactory) .setMinimumLoggingLevel(Log.VERBOSE) .build() } diff --git a/WorkManagerSample/app/src/main/java/com/example/background/FilterActivity.kt b/WorkManagerSample/app/src/main/java/com/example/background/FilterActivity.kt index 4060aa8d..41b38c1f 100644 --- a/WorkManagerSample/app/src/main/java/com/example/background/FilterActivity.kt +++ b/WorkManagerSample/app/src/main/java/com/example/background/FilterActivity.kt @@ -26,11 +26,13 @@ import androidx.appcompat.app.AppCompatActivity import androidx.work.WorkInfo import com.bumptech.glide.Glide import com.example.background.databinding.ActivityFilterBinding +import dagger.hilt.android.AndroidEntryPoint /** The [android.app.Activity] where the user picks filters to be applied on an image. */ +@AndroidEntryPoint class FilterActivity : AppCompatActivity() { - private val viewModel: FilterViewModel by viewModels { FilterViewModelFactory(application) } + private val viewModel: FilterViewModel by viewModels() private var outputImageUri: Uri? = null override fun onCreate(savedInstanceState: Bundle?) { diff --git a/WorkManagerSample/app/src/main/java/com/example/background/FilterViewModel.kt b/WorkManagerSample/app/src/main/java/com/example/background/FilterViewModel.kt index 992220ec..287e0a48 100644 --- a/WorkManagerSample/app/src/main/java/com/example/background/FilterViewModel.kt +++ b/WorkManagerSample/app/src/main/java/com/example/background/FilterViewModel.kt @@ -16,21 +16,22 @@ package com.example.background -import android.app.Application import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.map -import androidx.work.WorkInfo import androidx.work.WorkManager +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject /** * A [ViewModel] for [FilterActivity]. * * Keeps track of pending image filter operations. */ -class FilterViewModel(application: Application) : ViewModel() { +@HiltViewModel +class FilterViewModel @Inject constructor( + private val workManager: WorkManager +) : ViewModel() { - private val workManager = WorkManager.getInstance(application) + //private val workManager = WorkManager.getInstance(application) internal val workInfo = workManager.getWorkInfosByTagLiveData(Constants.TAG_OUTPUT) @@ -43,7 +44,7 @@ class FilterViewModel(application: Application) : ViewModel() { workManager.cancelUniqueWork(Constants.IMAGE_MANIPULATION_WORK_NAME) } } - +/* class FilterViewModelFactory(private val application: Application) : ViewModelProvider.Factory { override fun create(modelClass: Class): T { @@ -53,4 +54,4 @@ class FilterViewModelFactory(private val application: Application) : ViewModelPr throw IllegalArgumentException("Unknown ViewModel class") } } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/WorkManagerSample/app/src/main/java/com/example/background/SelectImageActivity.kt b/WorkManagerSample/app/src/main/java/com/example/background/SelectImageActivity.kt index a2017085..dd183bfd 100644 --- a/WorkManagerSample/app/src/main/java/com/example/background/SelectImageActivity.kt +++ b/WorkManagerSample/app/src/main/java/com/example/background/SelectImageActivity.kt @@ -34,6 +34,7 @@ import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import com.example.background.databinding.ActivitySelectBinding import com.google.android.material.snackbar.Snackbar +import dagger.hilt.android.AndroidEntryPoint import java.util.ArrayList /** @@ -41,6 +42,7 @@ import java.util.ArrayList * * There are two sources for the images: [MediaStore] and [StockImages]. */ +@AndroidEntryPoint class SelectImageActivity : AppCompatActivity() { private var permissionRequestCount = 0 diff --git a/WorkManagerSample/app/src/main/java/com/example/background/di/WorkManagerInitModule.kt b/WorkManagerSample/app/src/main/java/com/example/background/di/WorkManagerInitModule.kt index bdbf51b4..193d8306 100644 --- a/WorkManagerSample/app/src/main/java/com/example/background/di/WorkManagerInitModule.kt +++ b/WorkManagerSample/app/src/main/java/com/example/background/di/WorkManagerInitModule.kt @@ -1,4 +1,30 @@ package com.example.background.di -object WorkManagerInitModule { +import android.content.Context +import android.util.Log +import androidx.startup.Initializer +import androidx.work.Configuration +import androidx.work.WorkManager +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object WorkManagerInitModule : Initializer { + @Provides + @Singleton + override fun create(@ApplicationContext context: Context): WorkManager { + val configuration = Configuration.Builder().build() + WorkManager.initialize(context, configuration) + Log.d("Hilt Init", "WorkManager initialized by Hilt this time") + return WorkManager.getInstance(context) + } + + override fun dependencies(): List>> { + return emptyList() + } } \ No newline at end of file diff --git a/WorkManagerSample/build.gradle b/WorkManagerSample/build.gradle index 4083839e..881dab28 100644 --- a/WorkManagerSample/build.gradle +++ b/WorkManagerSample/build.gradle @@ -23,6 +23,7 @@ buildscript { dependencies { classpath "com.android.tools.build:gradle:${versions.android_gradle_plugin}" + classpath deps.hilt.hilt_gradle_plugin classpath deps.kotlin.plugin classpath deps.benchmark_gradle } diff --git a/WorkManagerSample/lib/build.gradle b/WorkManagerSample/lib/build.gradle index 25f9b78e..6a493159 100644 --- a/WorkManagerSample/lib/build.gradle +++ b/WorkManagerSample/lib/build.gradle @@ -16,6 +16,8 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' +apply plugin: 'dagger.hilt.android.plugin' android { compileSdkVersion build_versions.compile_sdk @@ -53,6 +55,10 @@ dependencies { implementation deps.retrofit.gson implementation deps.okhttp_logging_interceptor implementation deps.glide.runtime + implementation deps.hilt.hilt_common + implementation deps.hilt.dagger_hilt_android + implementation deps.hilt.hilt_work + kapt deps.hilt.hilt_compiler testImplementation deps.junit diff --git a/WorkManagerSample/lib/src/main/java/com/example/background/workers/CleanupWorker.kt b/WorkManagerSample/lib/src/main/java/com/example/background/workers/CleanupWorker.kt index 1b03e962..c399337e 100644 --- a/WorkManagerSample/lib/src/main/java/com/example/background/workers/CleanupWorker.kt +++ b/WorkManagerSample/lib/src/main/java/com/example/background/workers/CleanupWorker.kt @@ -19,15 +19,22 @@ package com.example.background.workers import android.content.Context import android.util.Log import androidx.annotation.VisibleForTesting +import androidx.hilt.work.HiltWorker import androidx.work.CoroutineWorker import androidx.work.WorkerParameters import com.example.background.Constants +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.io.File /** Clears temporary files. */ -class CleanupWorker(appContext: Context, workerParams: WorkerParameters) : +@HiltWorker +class CleanupWorker @AssistedInject constructor( + @Assisted appContext: Context, + @Assisted workerParams: WorkerParameters +) : CoroutineWorker(appContext, workerParams) { @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) diff --git a/WorkManagerSample/lib/src/main/java/com/example/background/workers/SaveImageToGalleryWorker.kt b/WorkManagerSample/lib/src/main/java/com/example/background/workers/SaveImageToGalleryWorker.kt index 681755d1..d733dca8 100644 --- a/WorkManagerSample/lib/src/main/java/com/example/background/workers/SaveImageToGalleryWorker.kt +++ b/WorkManagerSample/lib/src/main/java/com/example/background/workers/SaveImageToGalleryWorker.kt @@ -23,12 +23,15 @@ import android.net.Uri import android.provider.MediaStore import android.provider.MediaStore.Images.Media import android.util.Log +import androidx.hilt.work.HiltWorker import androidx.work.CoroutineWorker import androidx.work.Data import androidx.work.ForegroundInfo import androidx.work.WorkerParameters import com.example.background.Constants import com.example.background.library.R +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject import java.text.SimpleDateFormat import java.util.Date import java.util.Locale @@ -36,7 +39,11 @@ import java.util.Locale /** * Saves an output image to the [MediaStore]. */ -class SaveImageToGalleryWorker(appContext: Context, workerParams: WorkerParameters) : +@HiltWorker +class SaveImageToGalleryWorker @AssistedInject constructor( + @Assisted appContext: Context, + @Assisted workerParams: WorkerParameters +) : CoroutineWorker(appContext, workerParams) { override suspend fun doWork(): Result { @@ -70,8 +77,11 @@ class SaveImageToGalleryWorker(appContext: Context, workerParams: WorkerParamete override suspend fun getForegroundInfo(): ForegroundInfo { return ForegroundInfo( - NOTIFICATION_ID, createNotification(applicationContext, id, - applicationContext.getString(R.string.notification_title_saving_image))) + NOTIFICATION_ID, createNotification( + applicationContext, id, + applicationContext.getString(R.string.notification_title_saving_image) + ) + ) } companion object { diff --git a/WorkManagerSample/lib/src/main/java/com/example/background/workers/UploadWorker.kt b/WorkManagerSample/lib/src/main/java/com/example/background/workers/UploadWorker.kt index 96264c98..2ee1db04 100644 --- a/WorkManagerSample/lib/src/main/java/com/example/background/workers/UploadWorker.kt +++ b/WorkManagerSample/lib/src/main/java/com/example/background/workers/UploadWorker.kt @@ -20,17 +20,24 @@ import android.content.Context import android.net.Uri import android.util.Log import android.widget.Toast +import androidx.hilt.work.HiltWorker import androidx.work.Data import androidx.work.Worker import androidx.work.WorkerParameters import androidx.work.workDataOf import com.example.background.Constants import com.example.background.imgur.ImgurApi +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject /** * Uploads an image to Imgur using the [ImgurApi]. */ -class UploadWorker(appContext: Context, workerParams: WorkerParameters) : +@HiltWorker +class UploadWorker @AssistedInject constructor( + @Assisted appContext: Context, + @Assisted workerParams: WorkerParameters +) : Worker(appContext, workerParams) { override fun doWork(): Result { diff --git a/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/BaseFilterWorker.kt b/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/BaseFilterWorker.kt index 3ba6755b..350e986d 100644 --- a/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/BaseFilterWorker.kt +++ b/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/BaseFilterWorker.kt @@ -16,30 +16,31 @@ package com.example.background.workers.filters -import android.app.NotificationManager import android.content.Context import android.graphics.Bitmap import android.graphics.BitmapFactory import android.net.Uri import android.util.Log import androidx.annotation.VisibleForTesting -import androidx.work.* +import androidx.work.CoroutineWorker +import androidx.work.ForegroundInfo +import androidx.work.WorkerParameters +import androidx.work.workDataOf import com.example.background.Constants import com.example.background.library.R import com.example.background.workers.createNotification -import java.io.File -import java.io.FileNotFoundException -import java.io.FileOutputStream -import java.io.IOException -import java.io.InputStream -import java.util.UUID +import java.io.* +import java.util.* -abstract class BaseFilterWorker(context: Context, parameters: WorkerParameters) : +abstract class BaseFilterWorker( + context: Context, + parameters: WorkerParameters +) : CoroutineWorker(context, parameters) { override suspend fun doWork(): Result { - val resourceUri = inputData.getString(Constants.KEY_IMAGE_URI) ?: - throw IllegalArgumentException("Invalid input uri") + val resourceUri = inputData.getString(Constants.KEY_IMAGE_URI) + ?: throw IllegalArgumentException("Invalid input uri") return try { val inputStream = inputStreamFor(applicationContext, resourceUri) val bitmap = BitmapFactory.decodeStream(inputStream) @@ -95,13 +96,18 @@ abstract class BaseFilterWorker(context: Context, parameters: WorkerParameters) * Create ForegroundInfo required to run a Worker in a foreground service. */ override suspend fun getForegroundInfo(): ForegroundInfo { - return ForegroundInfo(NOTIFICATION_ID, createNotification(applicationContext, id, - applicationContext.getString(R.string.notification_title_filtering_image))) + return ForegroundInfo( + NOTIFICATION_ID, createNotification( + applicationContext, id, + applicationContext.getString(R.string.notification_title_filtering_image) + ) + ) } companion object { const val TAG = "BaseFilterWorker" const val ASSET_PREFIX = "file:///android_asset/" + // For a real world app you might want to use a different id for each Notification. const val NOTIFICATION_ID = 1 diff --git a/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/BlurEffectFilterWorker.kt b/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/BlurEffectFilterWorker.kt index e8040f86..74389628 100644 --- a/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/BlurEffectFilterWorker.kt +++ b/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/BlurEffectFilterWorker.kt @@ -22,9 +22,16 @@ import android.renderscript.Allocation import android.renderscript.Element import android.renderscript.RenderScript import android.renderscript.ScriptIntrinsicBlur +import androidx.hilt.work.HiltWorker import androidx.work.WorkerParameters +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject -class BlurEffectFilterWorker(context: Context, parameters: WorkerParameters) : +@HiltWorker +class BlurEffectFilterWorker @AssistedInject constructor( + @Assisted context: Context, + @Assisted parameters: WorkerParameters +) : BaseFilterWorker(context, parameters) { override fun applyFilter(input: Bitmap): Bitmap { diff --git a/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/GrayScaleFilterWorker.kt b/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/GrayScaleFilterWorker.kt index b213c1dd..f349023e 100644 --- a/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/GrayScaleFilterWorker.kt +++ b/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/GrayScaleFilterWorker.kt @@ -20,10 +20,17 @@ import android.content.Context import android.graphics.Bitmap import android.renderscript.Allocation import android.renderscript.RenderScript +import androidx.hilt.work.HiltWorker import androidx.work.WorkerParameters import com.example.background.ScriptC_grayscale +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject -class GrayScaleFilterWorker(context: Context, parameters: WorkerParameters) : +@HiltWorker +class GrayScaleFilterWorker @AssistedInject constructor( + @Assisted context: Context, + @Assisted parameters: WorkerParameters +) : BaseFilterWorker(context, parameters) { override fun applyFilter(input: Bitmap): Bitmap { diff --git a/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/WaterColorFilterWorker.kt b/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/WaterColorFilterWorker.kt index d9429535..d0c77d9b 100644 --- a/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/WaterColorFilterWorker.kt +++ b/WorkManagerSample/lib/src/main/java/com/example/background/workers/filters/WaterColorFilterWorker.kt @@ -20,10 +20,17 @@ import android.content.Context import android.graphics.Bitmap import android.renderscript.Allocation import android.renderscript.RenderScript +import androidx.hilt.work.HiltWorker import androidx.work.WorkerParameters import com.example.background.ScriptC_waterColorEffect +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject -class WaterColorFilterWorker(context: Context, parameters: WorkerParameters) : +@HiltWorker +class WaterColorFilterWorker @AssistedInject constructor( + @Assisted context: Context, + @Assisted parameters: WorkerParameters +) : BaseFilterWorker(context, parameters) { override fun applyFilter(input: Bitmap): Bitmap { diff --git a/WorkManagerSample/versions.gradle b/WorkManagerSample/versions.gradle index 7c8ecafa..71b4ba96 100644 --- a/WorkManagerSample/versions.gradle +++ b/WorkManagerSample/versions.gradle @@ -42,6 +42,10 @@ versions.espresso = "3.2.0" versions.fragment = "1.2.0" versions.glide = "4.8.0" versions.hamcrest = "1.3" +versions.hilt = "2.42" +versions.hilt_work = "1.0.0" +versions.hilt_common = "1.0.0" +versions.androidx_hilt_compiler = "1.0.0" versions.junit = "4.12" versions.kotlin = "1.6.10" versions.lifecycle = "2.2.0" @@ -59,10 +63,11 @@ versions.robolectric = "4.2" versions.room = "2.4.0-alpha05" versions.rx_android = "2.0.1" versions.rxjava2 = "2.1.3" +versions.startup = "1.1.1" versions.timber = "4.7.1" versions.transition = "1.3.0" versions.truth = "1.0.1" -versions.work = "2.7.0-rc01" +versions.work = "2.7.1" ext.versions = versions def build_versions = [:] @@ -84,6 +89,8 @@ deps.annotations = "androidx.annotation:annotation:$versions.annotations" deps.app_compat = "androidx.appcompat:appcompat:$versions.appcompat" +deps.app_startup = "androidx.startup:startup-runtime:$versions.startup" + def arch_core = [:] arch_core.runtime = "androidx.arch.core:core-runtime:$versions.arch_core" arch_core.testing = "androidx.arch.core:core-testing:$versions.arch_core" @@ -140,6 +147,15 @@ deps.glide = glide deps.hamcrest = "org.hamcrest:hamcrest-all:$versions.hamcrest" +def hilt = [:] +hilt.androidx_hilt_compiler = "androidx.hilt:hilt-compiler:$versions.androidx_hilt_compiler" +hilt.dagger_hilt_android = "com.google.dagger:hilt-android:$versions.hilt" +hilt.hilt_common = "androidx.hilt:hilt-common:${versions.hilt_common}" +hilt.hilt_compiler = "com.google.dagger:hilt-compiler:$versions.hilt" +hilt.hilt_gradle_plugin = "com.google.dagger:hilt-android-gradle-plugin:$versions.hilt" +hilt.hilt_work = "androidx.hilt:hilt-work:$versions.hilt_work" +deps.hilt = hilt + deps.junit = "junit:junit:$versions.junit" def kotlin = [:] @@ -225,4 +241,5 @@ def addRepos(RepositoryHandler handler) { handler.jcenter() handler.maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } } + ext.addRepos = this.&addRepos