androidrx-javarx-java2rx-kotlin2

How to use Rxjava for long running background task


I am using rxjava for some uploading task to server, Whenever task initiated fragment or activity is destroyed i will be disposing the subscription to avoid memory leak, But what i want is even after the fragment/activity destroyed i need to continue the task running in the background, Is there is any way to achieve this ?

Example

doSomeLongRunningBgTaks()
     .subscribe()
     .addTo(compositeDisposal)
override onDestroy(){
  compositeDisposal.clear()
}

Is it mandatory to dispose the subscription all time ? if not when to use dispose ?


Solution

  • First of all, you have to be aware of background task restriction of modern versions of AndroidOS. All about it here [a link] (https://developer.android.com/about/versions/oreo/background) In short, if your app is not visible or your app doesn't have running foreground service there is not any guarantee that your background work is completed.

    Secondly, in your case, you need to have some entity which is not tied to any lifecycle of your fragments or activity and able to run background work. There are several possible solutions

    1) Android service way

    Create an Intent service. It's a simple service with already implemented blocks which has internal Queue. Every time when a client tries to execute a job through such service, service executes such task in a background queue. So if you executes it twice, the service will wat first task completion before the execution of the second task.

    import android.app.IntentService import android.content.Intent

    class MyIntentService : IntentService("My intent service") {
    
      // This method already in another thread (not UI thread)
      override fun onHandleIntent(intent: Intent?) {
        doLongRunningBackgroundJob()
      }
    }
    

    P.S. Do not forget to register such service in the Manifest file.

    2) Android handler way

    You can create a class with an internal android handler with prepared background looper. For example:

    import android.os.Handler
    import android.os.HandlerThread
    
    class MyBackgroundWorker {
    
      private val handler = initHandler()
    
      private fun initHandler(): Handler {
        val handlerThread = HandlerThread("My background thread")
        handlerThread.start()
        return Handler(handlerThread.looper)
      }
    
      fun executeJobInBackground(job: Runnable) {
        handler.post(job)
      }
    }
    

    3) Pure java way

    You can create an instance of pure thread, but more preferable to use executors Java framework. For the thread approach:

    class MyBackgroundWorker {
    
      fun executeJobInBackground(job: Runnable) {
        Thread(job).start()
      }
    }
    

    For the executor approach:

    import java.util.concurrent.Executors
    
    class MyBackgroundWorker {
    
      private val executor = Executors.newSingleThreadExecutor()
    
      fun executeJobInBackground(job: Runnable) {
        executor.execute(job)
      }
    }
    

    P.S. Do not forget to provide dependencies using DI approach.