Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?
like image 594
Igor Escodro Avatar asked Oct 15 '18 23:10

Igor Escodro


1 Answers

  • Yes WorkManager is a good solution(even could be the best one)
  • You should use RxWorker instead of Worker. here is an example:

    1. To implement it. add androidx.work:work-rxjava2:$work_version to your build.gradle file as dependency.

    2. 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
like image 60
sma6871 Avatar answered Oct 31 '22 05:10

sma6871