Skip to content

Commit 6de0b70

Browse files
committed
add chaining work
1 parent c13fac6 commit 6de0b70

File tree

5 files changed

+151
-4
lines changed

5 files changed

+151
-4
lines changed

11-blur-o-matic/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ An app that blurs photos and saves the result to a file, using WorkManager.
1212
- scheduling a simple task.
1313
- handling input and output parameters.
1414
- chaining work.
15+
- ensuring unique work.
1516
- displaying work status in the UI.
17+
- showing final output.
1618
- cancelling work.
1719

1820
Based on [Background work with WorkManager - Kotlin](https://developer.android.com/codelabs/android-workmanager) by Google Codelabs (2022).

11-blur-o-matic/app/src/main/java/com/example/background/BlurViewModel.kt

+40-1
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,14 @@ import android.content.Context
2222
import android.net.Uri
2323
import androidx.lifecycle.ViewModel
2424
import androidx.lifecycle.ViewModelProvider
25+
import androidx.work.Data
2526
import androidx.work.OneTimeWorkRequest
27+
//import androidx.work.OneTimeWorkRequest
28+
import androidx.work.OneTimeWorkRequestBuilder
2629
import androidx.work.WorkManager
2730
import com.example.background.workers.BlurWorker
31+
import com.example.background.workers.CleanupWorker
32+
import com.example.background.workers.SaveImageToFileWorker
2833

2934

3035
class BlurViewModel(application: Application) : ViewModel() {
@@ -40,7 +45,33 @@ class BlurViewModel(application: Application) : ViewModel() {
4045
* @param blurLevel The amount to blur the image
4146
*/
4247
internal fun applyBlur(blurLevel: Int) {
43-
workManager.enqueue(OneTimeWorkRequest.from(BlurWorker::class.java))
48+
//workManager.enqueue(OneTimeWorkRequest.from(BlurWorker::class.java))
49+
50+
// add input and output
51+
/*val blurRequest = OneTimeWorkRequestBuilder<BlurWorker>()
52+
.setInputData(createInputDataForUri())
53+
.build()
54+
55+
workManager.enqueue(blurRequest)*/
56+
57+
// chain your work
58+
// add work request to clean up temporary images
59+
var continuation = workManager
60+
.beginWith(OneTimeWorkRequest.from(CleanupWorker::class.java))
61+
// add work request to blur the image the number of times requested
62+
for (i in 0 until blurLevel) {
63+
val blurBuilder = OneTimeWorkRequestBuilder<BlurWorker>()
64+
if (i == 0) {
65+
blurBuilder.setInputData(createInputDataForUri())
66+
}
67+
continuation = continuation.then(blurBuilder.build())
68+
}
69+
// add work request to save the image to the filesystem
70+
val save = OneTimeWorkRequest.Builder(SaveImageToFileWorker::class.java).build()
71+
continuation = continuation.then(save)
72+
73+
// actually start the work
74+
continuation.enqueue()
4475
}
4576

4677
private fun uriOrNull(uriString: String?): Uri? {
@@ -64,6 +95,14 @@ class BlurViewModel(application: Application) : ViewModel() {
6495
return imageUri
6596
}
6697

98+
private fun createInputDataForUri() : Data {
99+
val builder = Data.Builder()
100+
imageUri?.let {
101+
builder.putString(KEY_IMAGE_URI, imageUri.toString())
102+
}
103+
return builder.build()
104+
}
105+
67106
internal fun setOutputUri(outputImageUri: String?) {
68107
outputUri = uriOrNull(outputImageUri)
69108
}

11-blur-o-matic/app/src/main/java/com/example/background/workers/BlurWorker.kt

+21-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ package com.example.background.workers
22

33
import android.content.Context
44
import android.graphics.BitmapFactory
5+
import android.net.Uri
6+
import android.text.TextUtils
57
import android.util.Log
68
import androidx.work.Worker
79
import androidx.work.WorkerParameters
10+
import androidx.work.workDataOf
11+
import com.example.background.KEY_IMAGE_URI
812
import com.example.background.R
913

1014
private const val TAG = "BlurWorker"
@@ -14,20 +18,34 @@ class BlurWorker(ctx: Context, params: WorkerParameters) : Worker(ctx, params) {
1418
override fun doWork(): Result {
1519
val appContext = applicationContext
1620
makeStatusNotification("Blurring image", appContext)
21+
// slows down the worker
22+
sleep()
23+
val resourceUri = inputData.getString(KEY_IMAGE_URI)
1724

1825
return try {
19-
val picture = BitmapFactory.decodeResource(
26+
/*val picture = BitmapFactory.decodeResource(
2027
appContext.resources,
2128
R.drawable.android_cupcake
29+
)*/
30+
if (TextUtils.isEmpty(resourceUri)) {
31+
Log.e(TAG, "Invalid input uri")
32+
throw IllegalArgumentException("Invalid input uri")
33+
}
34+
val resolver = appContext.contentResolver
35+
val picture = BitmapFactory.decodeStream(
36+
resolver.openInputStream(Uri.parse(resourceUri))
2237
)
38+
2339
val output = blurBitmap(picture, appContext)
2440

2541
// Write bitmap to a temp file
2642
val outputUri = writeBitmapToFile(appContext, output)
27-
makeStatusNotification("Output is $outputUri", appContext)
28-
Result.success()
43+
//makeStatusNotification("Output is $outputUri", appContext)
44+
val outputData = workDataOf(KEY_IMAGE_URI to outputUri.toString())
45+
Result.success(outputData)
2946
} catch (throwable: Throwable) {
3047
Log.e(TAG, "Error applying blur")
48+
throwable.printStackTrace()
3149
Result.failure()
3250
}
3351
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.example.background.workers
2+
3+
import android.content.Context
4+
import android.util.Log
5+
import androidx.work.Worker
6+
import androidx.work.WorkerParameters
7+
import com.example.background.OUTPUT_PATH
8+
import java.io.File
9+
10+
// cleans up temporary files generated during blurring process
11+
private const val TAG = "CleanupWorker"
12+
class CleanupWorker(ctx: Context, params: WorkerParameters) : Worker(ctx, params) {
13+
14+
override fun doWork(): Result {
15+
// slows downs the work to see each WorkRequest start
16+
makeStatusNotification("Cleaning up old temporary files", applicationContext)
17+
sleep()
18+
19+
return try {
20+
val outputDirectory = File(applicationContext.filesDir, OUTPUT_PATH)
21+
if (outputDirectory.exists()) {
22+
val entries = outputDirectory.listFiles()
23+
if (entries != null) {
24+
for (entry in entries) {
25+
val name = entry.name
26+
if (name.isNotEmpty() && name.endsWith(".png")) {
27+
val deleted = entry.delete()
28+
Log.i(TAG, "Deleted $name - $deleted")
29+
}
30+
}
31+
}
32+
}
33+
Result.success()
34+
} catch (exception: Exception) {
35+
exception.printStackTrace()
36+
Result.failure()
37+
}
38+
}
39+
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.example.background.workers
2+
3+
import android.content.Context
4+
import android.graphics.BitmapFactory
5+
import android.net.Uri
6+
import android.provider.MediaStore
7+
import android.util.Log
8+
import androidx.work.Worker
9+
import androidx.work.WorkerParameters
10+
import androidx.work.workDataOf
11+
import com.example.background.KEY_IMAGE_URI
12+
import java.text.SimpleDateFormat
13+
import java.util.*
14+
15+
// saves the image to a permanent file
16+
private const val TAG = "SaveImageToFileWorker"
17+
class SaveImageToFileWorker(ctx: Context, params: WorkerParameters) : Worker(ctx, params) {
18+
private val title = "Blurred Image"
19+
private val dateFormatter = SimpleDateFormat(
20+
"yyyy.MM.dd 'at' HH:mm:ss z",
21+
Locale.getDefault()
22+
)
23+
24+
override fun doWork(): Result {
25+
// slows downs the work to see each WorkRequest start
26+
makeStatusNotification("Saving image", applicationContext)
27+
sleep()
28+
29+
val resolver = applicationContext.contentResolver
30+
return try {
31+
val resourceUri = inputData.getString(KEY_IMAGE_URI)
32+
val bitmap = BitmapFactory.decodeStream(
33+
resolver.openInputStream(Uri.parse(resourceUri)))
34+
val imageUrl = MediaStore.Images.Media.insertImage(
35+
resolver, bitmap, title, dateFormatter.format(Date()))
36+
if (!imageUrl.isNullOrEmpty()) {
37+
val output = workDataOf(KEY_IMAGE_URI to imageUrl)
38+
Result.success(output)
39+
} else {
40+
Log.e(TAG, "Writing to MediaStore failed")
41+
Result.failure()
42+
}
43+
} catch (exception: Exception) {
44+
exception.printStackTrace()
45+
Result.failure()
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)