Как использовать Rxjava для длительной фоновой задачи

Я использую rxjava для какой-либо задачи загрузки на сервер. Всякий раз, когда фрагмент или действие, инициированное задачей, уничтожается, я буду удалять подписку, чтобы избежать утечки памяти. Но я хочу, чтобы даже после уничтожения фрагмента/действия мне нужно было продолжить выполнение задачи в фон, есть ли способ добиться этого?

Пример

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

Обязательно ли удалять подписку все время? если нет, когда использовать dispose ?


person Stack    schedule 11.09.2019    source источник
comment
Используйте службу переднего плана, чтобы пользователь знал, что выполняется какая-то задача. Фоновые службы не идеальны, потому что большинство OEM-производителей Android убьют вашу фоновую службу. Или вы можете допустить утечку памяти на некоторое время, если длительная задача не такая длинная (см. здесь: stackoverflow.com/a /43546277/2235972)   -  person denvercoder9    schedule 11.09.2019


Ответы (3)


Прежде всего, вы должны знать об ограничении фоновых задач современных версий AndroidOS. Все об этом здесь [ссылка] (https://developer.android.com/about/versions/oreo/background) Короче говоря, если ваше приложение не отображается или в вашем приложении не запущена служба переднего плана, нет никакой гарантии, что ваша фоновая работа будет завершена.

Во-вторых, в вашем случае вам нужно иметь некую сущность, которая не привязана ни к какому жизненному циклу ваших фрагментов или активности и способна выполнять фоновую работу. Есть несколько возможных решений

1) Способ службы Android

Создайте службу намерения. Это простой сервис с уже реализованными блоками, который имеет внутреннюю очередь. Каждый раз, когда клиент пытается выполнить задание через такой сервис, сервис выполняет такое задание в фоновой очереди. Поэтому, если вы выполните его дважды, служба будет ожидать завершения первой задачи до выполнения второй задачи.

импортировать android.app.IntentService импортировать 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. Не забудьте зарегистрировать такой сервис в файле манифеста.

2) Способ обработчика Android

Вы можете создать класс с внутренним обработчиком Android с подготовленным фоновым циклером. Например:

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) Чистый Java-способ

Можно создать экземпляр чистого потока, но предпочтительнее использовать исполнители Java framework. Для потокового подхода:

class MyBackgroundWorker {

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

Для подхода исполнителя:

import java.util.concurrent.Executors

class MyBackgroundWorker {

  private val executor = Executors.newSingleThreadExecutor()

  fun executeJobInBackground(job: Runnable) {
    executor.execute(job)
  }
}

P.S. Не забудьте предоставить зависимости, используя подход DI.

person Oleg Kuzmin    schedule 11.09.2019
comment
работает ли это для приложения, очищенного от последних приложений (означает, что я хочу запустить службу ForeGround или службу Intent в фоновом режиме, когда приложение было очищено из стека) - person satyan_android; 18.09.2019

Итак, зачем вам одноразовые?

Итак, если у вас есть некоторые наблюдаемые, как показано ниже:

Observable.just("Hello world!")
     .delay(1, TimeUnit.SECONDS)
     .subscribeWith(new DisposableObserver<String>() {
         @Override public void onStart() {
             System.out.println("Start!");
         }
         @Override public void onNext(String t) {
             System.out.println(t);
         }
         @Override public void onError(Throwable t) {
             t.printStackTrace();
         }
         @Override public void onComplete() {
             System.out.println("Done!");
         }
     });

теперь, если вы хотите остановить эту задачу, она удаляется только с помощью dispose().

Некоторое время, если пользователь хочет удалить какую-либо задачу, например: если пользователь переходит с экрана или пользователь нажимает кнопку «Назад», тогда мы должны завершить веб-запрос или отменить любую задачу в это время. Используется Disposable.

Что делать, если вам нужно выполнить какую-либо задачу в фоновом режиме и не убить, если фрагмент будет уничтожен?

Вы можете просто написать только метод subscribe() и забыть о задаче.

doSomeLongRunningBgTaks()
     .subscribe()

Может быть, это поможет вам. Спасибо

person Mahavir Jain    schedule 11.09.2019

Вы можете использовать что-то вроде этого:

webService.doSomething(someData)
      .observeOn(AndroidSchedulers.mainThread())
      .subscribe(
          result -> resultText.setText("It worked!"),
          e -> handleError(e));
person Deepak Rajput    schedule 11.09.2019
comment
Это не отвечает на вопрос - person denvercoder9; 11.09.2019
comment
@Deepak, это не тот ответ, которого я ожидал. - person Stack; 11.09.2019
comment
Какую длительную задачу вы хотите выполнить? - person Deepak Rajput; 11.09.2019