Android: как использовать JobFinished из JobService

Я не видел примера использования jobFinshed из JobService, похоже, мы должны отслеживать изменения, когда выполняется какое-то условие, мы должны вызывать метод jobFinished(), я прав?


person blackHawk    schedule 14.06.2017    source источник


Ответы (4)


Сложность вызова jobFinished() из другого класса, такого как IntentService, похоже, заключается в получении экземпляра вашего класса, который расширяет JobService для использования для вызова jobFinished(). Вы можете получить информацию о запланированной работе, но не о JobService (по крайней мере, я не могу найти способ). Я могу придумать 3 способа вызова jobFinished().

Если вам все равно, успешна ваша работа или нет, или если ваша работа занимает очень мало времени.

В одном из моих JobService классов я выполняю периодическую работу. Я не беспокоюсь о том, как справляться с неудачами. Задача будет выполнена снова достаточно скоро. Если это так, вы можете сделать это.

    public boolean onStartJob(JobParameters params) {
        startService(new Intent(this, MyIntentServiceThatDoesTheWork.class));

        // job not really finished here but we assume success & prevent backoff procedures, wakelocking, etc.
        jobFinished(params, false);
        return true;
    }

Это также то, как вы хотите сделать это, если ваша работа достаточно коротка, это не проблема сделать это в потоке пользовательского интерфейса. В этом случае выполните всю свою работу в onStartJob(), а затем верните false.

Используйте BroadcastReceiver для отправки сообщения из IntentService в JobService (отдельный файл для каждого класса).

    // common Strings
    public static final String IS_SUCCESS = "isSuccess";
    public static final String MY_BC_RCVR = "MyBroadcastRcvr";

Ваш JobService

    public class MyJobService extends JobService {
        JobParameters mParams;

        public boolean onStartJob(JobParameters params) {
            mParams = params;
            LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
                    new IntentFilter(MY_BC_RCVR));
            startService(new Intent(this, MyIntentServiceThatDoesTheWork.class));
            return true;
        }

        private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                boolean isSuccess = false;
                if(intent.hasExtra(IS_SUCCESS)) {
                    isSuccess = intent.getBooleanExtra(IS_SUCCESS, false);
                }
                LocalBroadcastManager.getInstance(context).unregisterReceiver(this);
                jobFinished(mParams, !isSuccess);
            }
        };
    }

и ваш IntentService

    public class MyIntentServiceThatDoesTheWork extends IntentService {
        @Override
        protected void onHandleIntent(Intent intent) {

            boolean isSuccess = methodToDoAllMyWork();
            Intent bcIntent = new Intent(MY_BC_RCVR);
            bcIntent.putExtra(IS_SUCCESS, isSuccess);
            LocalBroadcastManager.getInstance(this).sendBroadcast(bcIntent);
        }
    }

Вложите класс рабочего потока в класс JobService.

Я привел пример AsyncTask на основе этого Пост на среднем уровне (на который также ссылается Арсений Левин) от Google Developer Advocate, но также должна быть возможность использовать IntentService (см. этот SO post для вложения IntentService).

    public class MyJobService extends JobService {
        JobParameters mParams;

        public boolean onStartJob(JobParameters params) {
            mParams = params;
            new MyAsyncTaskThatDoesTheWork().execute();
            return true;
        }

        private class MyAsyncTaskThatDoesTheWork extends AsyncTask<Void, Void, Boolean> {
            @Override
            protected Boolean doInBackground(Void... params) {
                return methodToDoAllMyWork();
            }

            @Override
            protected void onPostExecute(Boolean isSuccess) {
                if(mParams != null) {
                    jobFinished(mParams, !isSuccess);
                }
            }
        }
    }
person Gary99    schedule 18.12.2017
comment
подход с InentService + LocalBroadcastManager отлично работает. Но ваш первый пример кода, в котором вы запускаете службу и мгновенно вызываете jobFinished(params, false); это не очень хорошая идея. Это может остановить выполнение рабочего потока в середине чего-то, что может привести к неожиданному состоянию и/или поведению. Если ваша работа выполняется быстро, используйте AsyncTask, если требуется некоторое время, используйте IntentService + LocalBroadcasting, чтобы завершить работу должным образом. - person Kirill Karmazin; 28.02.2018
comment
Нужно ли вызывать LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver) в методе onStopJob и методе BroadcastReceiver::onReceive? - person Jsyntax; 06.09.2018
comment
Обновление: я попробовал startService (2-й подход) в JobService, и когда мое приложение перешло в фоновый режим, задание не смогло запустить службу (IllegalStateException). запустить новую фоновую службу и т. д.), но, по-видимому, вы не можете. В итоге я начал JobIntentService с JobService. На данный момент JobService является избыточным, но я хотел сохранить проверку ограничений, предусмотренную планировщиком заданий. - person Jsyntax; 06.09.2018

Если ваш метод onStartJob() возвращает true, это означает, что вы выполняете работу в фоновом режиме в поддержку этой работы. Этот фоновый поток должен вызвать jobFinished(), когда эта работа будет завершена или если задание необходимо перепланировать.

person CommonsWare    schedule 14.06.2017
comment
Как лучше всего установить сетевое соединение со службой занятости? Остается ли соединение установленным, когда мы вызываем jobfinished? - person neoexpert; 11.01.2019
comment
@neoexpert: Будет ли соединение оставаться установленным, когда мы назовем jobfinished? -- не стоит на это рассчитывать. Насколько я знаю, ваша служба будет уничтожена, когда не будет активных заданий. Как лучше всего установить сетевое соединение со службой занятости? -- Выполняйте весь сетевой ввод-вывод в рамках задания, максимальное время выполнения которого составляет примерно 10 минут. Или, быть в состоянии продолжить, где вы остановились с новым соединением. Или не используйте JobService. - person CommonsWare; 11.01.2019

Простой подход — запустить новый поток из onStartJob, как показано ниже:

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class MyJobService extends JobService {
    @Override
    public boolean onStartJob(final JobParameters params) {
      new Thread(new Runnable() {
        @Override
        public void run() {

            // do your job here

            jobFinished(params, true);
        }
      }).start();

      return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
      return true;
    }
}
person Ashwin    schedule 17.06.2019

Как объяснил @CommonsWare, внутри onStartJob вы решите, требуется ли дальнейшая работа в фоновом потоке. Только в этом случае вы должны вызвать jobFinished из этого фонового потока. Просто чтобы ответить на ваш конкретный вопрос - от вашего имени не требуется отслеживание условий. JobService позвонит onStopJob, если заданные вами условия перестанут выполняться.

Пример jobFinished можно найти здесь: https://medium.com/google-developers/scheduling-jobs-like-a-pro-with-jobscheduler-286ef8510129

person Arseny Levin    schedule 25.07.2017