Служба фоновых заданий Android на сопрограмме и Dispatcher.IO

#android #kotlin-coroutines

Вопрос:

Контекст

Я пытаюсь обновить пару фоновых заданий в Android 6. Основная цель состоит в том, чтобы сделать работу, выполняемую с помощью фонового задания, легкой и без блокировки потоков пользовательского интерфейса. Поэтому я решил кое-что сделать:

  • GlobalScope может быть плохой идеей, так как умирающий поток завершит остальные. Так что сопрограмма поможет вам в этом
  • Поскольку мне нужны операции ввода-вывода и сетевые функции, мне нужен пул потоков, предназначенный для этих задач. Поэтому я буду использовать Dispatchers.IO
  • Работа связанных служб занятости предназначена для «увольнения и забвения». Приложению все равно — поэтому я просто запущу задание, вместо того чтобы ждать вывода асинхронного

Код

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

 import android.app.job.JobParameters
import android.app.job.JobService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

class TestJobService : JobService() {

    override fun onStartJob(params: JobParameters?): Boolean {
        CoroutineScope(Dispatchers.IO).launch {
            // Fire and Forget
        }
        return false
    }

    override fun onStopJob(params: JobParameters?): Boolean {
        return false
    }
}
 

Вопросы

Если вы хотите ответить, пожалуйста, используйте номер вопроса.

  1. Является ли сопрограмма хорошей идеей?
  2. Я получаю ошибки из основного потока «I/art: Примечание: время окончания превышает эпоху:» — это сбивает с толку и может указывать на то, что служба заданий выполняет большую работу в потоке пользовательского интерфейса. Но у меня нет ошибок от хореографа, которые обычно должны иметь место, если пользовательский интерфейс в беде.
  3. Это плохая идея возвращать false в функциях JobService

Используемые в настоящее время Ссылки

https://medium.com/androiddevelopers/coroutines-on-android-part-i-getting-the-background-3e0e54d20bb
https://medium.com/androiddevelopers/coroutines-on-android-part-ii-getting-started-3bff117176dd
https://medium.com/androiddevelopers/coroutines-on-android-part-iii-real-work-2ba8a2ec2f45
https://developer.android.com/kotlin/coroutines/coroutines-adv?hl=de#coroutinescope
https://kotlinlang.org/docs/coroutines-basics.html#extract-function-refactoring

Ответ №1:

  1. Единственное, что делает ваше использование CoroutineScope , — это предоставляет IO диспетчера. В нынешнем виде, если какая-либо работа, выполненная в сопрограмме, вызовет исключение, вся область будет отменена. Это может быть проблемой, если вы запускаете несколько сопрограмм из него. Если вы действительно заботитесь об этом, вам также нужно будет настроить его с SupervisorJob помощью : CoroutineScope(Dispatchers.IO) SupervisorJob() .
  2. Трудно определить значение этой ошибки без вашего фактического кода. Из быстрого исследования, если вы сделаете что-то, что должно происходить только в основном потоке (например, возможно, доступ к определенным компонентам Android), это может привести к этой ошибке. Возможно, проверьте свой код на наличие таких случаев и заверните его в:
 withContext(Dispatchers.Main) { ... }
 

Но опять же, это всего лишь предположение без какого-либо фактического кода.

  1. В документах указано, что для onStartJob :

Система удерживает блокировку от имени вашего приложения до тех пор, пока выполняется ваша работа. Эта блокировка срабатывания приобретается до вызова этого метода и не освобождается до тех пор, пока вы не вызовете jobFinished(логические параметры android.app.job.job) или после того, как система вызовет onStopJob(параметры android.app.job.job), чтобы уведомить вашу работу о преждевременном закрытии.

Возврат false из этого метода означает, что ваша работа уже завершена. Блокировка пробуждения системы для задания будет выпущена, и onStopJob(параметры android.app.job.job) не будет вызываться.

И согласно документам wakelock,

Блокировка пробуждения — это механизм, указывающий, что вашему приложению необходимо, чтобы устройство оставалось включенным.

Так что нет, кажется неправильным возвращаться false из onStartJob , так как JobService не будет должным образом поддерживать wakelock. Чтобы исправить это, вы должны вернуться true из этого метода, и по завершении сопрограммы вы должны позвонить jobFinished , чтобы указать, что задание выполнило всю свою работу.

Для onStopJob возвращаемых значений:

значение true указывает менеджеру по работе, хотите ли вы перенести это задание на основе критериев повторной попытки, предоставленных во время создания задания; или значение false, чтобы полностью завершить задание. Независимо от возвращенного значения, ваше задание должно прекратиться.

В этом случае трудно определить правильное значение на основе вашего фрагмента. Вы должны быть в состоянии определить, что правильно, исходя из вашего варианта использования. В этом методе вы должны отменить ранее созданные CoroutineScope . Для этого вам нужно будет сохранить ссылку на область действия.