Method doWork() not calling with WorkManager - android

I need to upload file from device to my app. I use WorkManager to do it in background.
After updating library from android.arch.work:work-runtime:1.0.0-alpha04 to androidx.work:work-runtime:2.0.0 something goes wrong.
Method doWork() not calling in my UploadFileTask(workerParams: WorkerParameters) : Worker(Application.getContext(), workerParams)
Here is how I run my uploading:
fun upload(id: String, file: File, params: FileStorage.DocParams?, additionalTag: String): File {
cancelUploadIfWas(file)
fileStorage.save(file, params)
val inputData = Data.Builder().putString(FileTask.PATH_KEY, file.path).build()
val uploadWork = OneTimeWorkRequest.Builder(UploadFileTask::class.java)
.addTag(ID_PREFIX + id)
.addTag(PATH_PREFIX + file.path)
.addTag(UPLOAD_TAG)
.addTag(additionalTag)
.keepResultsForAtLeast(0, TimeUnit.SECONDS)
.setInputData(inputData)
.build()
workManager.enqueue(uploadWork)
file.uploadStatus.onLoading()
file.uploadWork=uploadWork
uploadingFiles.put(ID_PREFIX + id, file)
workManager.getWorkInfoByIdLiveData(uploadWork.id).observe(this, uploadObserver)
return file
}
But my uploadObserver receives State.FAILED exactly after State.ENQUEUED
What I'm doing wrong?

Solved
The trick was in that we have to create out task by this way:
UploadFileTask(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams)
The constructor of our task have to receive exactly two parameters: context: Context and workerParams: WorkerParameters
Explanation:
val downloadWork = OneTimeWorkRequest.Builder(downloadingTask)
.addTag(ID_TAG)
.keepResultsForAtLeast(0, TimeUnit.SECONDS)
.build()
workManager.enqueue(downloadWork)
WorkManager expects to receive downloadWork which was biult with downloadingTask, that has exactly two params in its constructor

Have you tried to check the size of your payload/data that you're sending to your worker?
Sometimes when your data object is too large for the worker limits, the doWork() may not be called.
Or, it could be some exception thrown in your doWork() method without you noticing it, so it's failing to proceed with further code executions.
You can try to:
Remove setInputData() from your upload method
Remove getInputData() from your WorkManager class
Now a Log to your doWork() method to check if it's being called

Related

How can I download files in specific days? [ Kotlin Android Development ]

What is a safe and greater method to execute tasks ( in my case call a function ) in specific time ( in my case every two days ) ?
The function retrieves data from the Web. My target is update the data in app whenever it changes on the webserver.
Thanks, good job!
1- If you don't need to be exact about time, you need to use WorkManager and set periodic work request
https://developer.android.com/topic/libraries/architecture/workmanager
fun CreateWorkRequest()
{
val workManager = WorkManager.getInstance(context)
val duration = 2*24*60*60*1000L //2 days in mili second
val workRequest = PeriodicWorkRequestBuilder<AutoBackUpWorker>(duration, TimeUnit.MILLISECONDS)
.setInitialDelay(duration/2, TimeUnit.MILLISECONDS)
.addTag("diaryBackUpWork")
.build()
workManager.enqueueUniquePeriodicWork("backupwork", ExistingPeriodicWorkPolicy.REPLACE, autoBackUpRequest)
}
Worker Class:
class RequestedWorker(val appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams)
{
override fun doWork()
{
}
}
2- If you need to be exact about time (like at 8pm everyday) you need to use Alarm Manager
3- In your case the best choice is implementing DownloadManager for download request in the doWork() method

Schedule task to be executed later (time + date) android

I just search for code that let me do an action after the timer (with specific date and time) finish (in Kotlin) and save it in a list
Like timer for post a tweet on Twitter:
https://business.twitter.com/en/help/campaign-editing-and-optimization/scheduled-tweets.html
You can use WorkManager for that.
Dependency:
implementation "androidx.work:work-runtime-ktx:2.3.0"
Example:
class LogWorker(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) {
override fun doWork(): Result {
// Do the work here--in this case, upload the images.
Log.i("ToastWorker", "doWork: Working ⚒ ⚒ ⚒")
// Indicate whether the task finished successfully with the Result
return Result.success()
}
}
Then set the delay time
val logWorkRequest = OneTimeWorkRequestBuilder<LogWorker>()
.setInitialDelay(5, TimeUnit.SECONDS) // here you can set the delay time in Minutes, Hours
.build()
Start the timer
WorkManager.getInstance(this).enqueue(toastWorkRequest)
Here is a Codelab for more insight. You can also read more here

How to handle asynchronous operation in Workmanager Android?

I am using workmanager to upload image file to server and want to pass uploaded imagepath to next worker but Result.success(output) gets called before upload function complete.
class UploadImageWorker(context: Context, workerParameters: WorkerParameters) : RxWorker(context, workerParameters) {
override fun createWork(): Single<Result> {
return Single.fromCallable {
//UploadImageFile()
//updating output
}.map{
Result.success(output)
}
}
}
Success, in this case, is only reporting that the job fired successfully, it is not a measure of the work itself.
You should just use the worker to hand off the work and do something like:
MyFactory.ImageFactory.UploadImageFile(file)
Then inside your ImageFactory use Observer pattern or something similar to subscribe to the state of your UploadImageFile. This would be the true measure of success.
You should use RxWorker. You can return a Single<Result>. Read the documentation for RxWorker for more information.
https://developer.android.com/reference/androidx/work/RxWorker

Android WorkManager doWork() run repeatedly even after task successfully completed

I am using Android WorkManager(version 1.0.0-alpha13) to get some data from my server and store it on local database. Used following worker, without any operations and just returned success. doWork() run repeatedly,even after task successfully completed. Is it normal behaviour of Worker or is it any issue in this version?
HomeRepository.kt
val fetchVideosWorker = OneTimeWorkRequest.Builder(FetchVideosWorker::class.java)
.build()
val enqueue = WorkManager.getInstance().enqueue(fetchVideosWorker)
FetchVideosWorker.kt
class FetchVideosWorker(context : Context, params : WorkerParameters) : Worker(context,params) {
override fun doWork(): Result {
Log.d("youtubevideo","doWork")
return Result.success()
}
}

How to dispose Rx in WorkManager?

I implemented an AlarmManager to send notifications when user adds a due date to a Task. However, when the user turns off the device, all the alarms are lost. Now I'm updating the BroadcastReceiver to receive an android.intent.action.BOOT_COMPLETED and reschedule all the alarms set to each task.
My first attempt was to get an Rx Single with all the tasks where the due date is higher than the current time inside the BroadcastReceiver, then reschedule all the alarms. The issue is I'm not able to dispose the Observable once the BroadcastReceiver has no lifecycle. Also, it seems that this is not a good approach.
During my researches, the IntentService was a good solution for this case, but I'm getting into the new WorkManager library and the OneTimeWorkRequest looks like a good and simple solution.
The Worker is being called and executing correctly, but I'm not able to dispose the Observable because the onStopped method is never called.
Here is the implementation, based on this snippet:
class TaskAlarmWorker(context: Context, params: WorkerParameters) :
Worker(context, params), KoinComponent {
private val daoRepository: DaoRepository by inject()
private val compositeDisposable = CompositeDisposable()
override fun doWork(): Result {
Timber.d("doWork")
val result = LinkedBlockingQueue<Result>()
val disposable =
daoRepository.getTaskDao().getAllTasks().applySchedulers().subscribe(
{ result.put(Result.SUCCESS) },
{ result.put(Result.FAILURE) }
)
compositeDisposable.add(disposable)
return try {
result.take()
} catch (e: InterruptedException) {
Result.RETRY
}
}
override fun onStopped(cancelled: Boolean) {
Timber.d("onStopped")
compositeDisposable.clear()
}
}
Is WorkManager a good solution for this case?
Is it possible to dispose the Observable correctly?
Yes WorkManager is a good solution(even could be the best one)
You should use RxWorker instead of Worker. here is an example:
To implement it. add androidx.work:work-rxjava2:$work_version to your build.gradle file as dependency.
Extend your class from RxWorker class, then override createWork() function.
class TaskAlarmWorker(context: Context, params: WorkerParameters) :
RxWorker(context, params), KoinComponent {
private val daoRepository: DaoRepository by inject()
override fun createWork(): Single<Result> {
Timber.d("doRxWork")
return daoRepository.getTaskDao().getAllTasks()
.doOnSuccess { /* process result somehow */ }
.map { Result.success() }
.onErrorReturn { Result.failure() }
}
}
Important notes about RxWorker:
The createWork() method is called on the main thread but returned single is subscribed on the background thread.
You don’t need to worry about disposing the Observer since RxWorker will dispose it automatically when the work stops.
Both returning Single with the value Result.failure() and single with an error will cause the worker to enter the failed state.
You can override onStopped function to do more.
Read more :
How to use WorkManager with RxJava
Stackoverflow answer
You can clear it in onStoped() method then compositeDisposable.dispose();
Then call super.onStoped()

Categories

Resources