WorkManager to biblioteka do planowania i wykonywania pracy w tle z możliwością odroczenia na Androidzie. Jest to zalecany zamiennik Firebase JobDispatcher. ten przewodnik poprowadzi Cię przez proces migracji Firebase Implementacja JobDispatcher w WorkManager.
Konfiguracja Gradle
Aby zaimportować bibliotekę WorkManager do projektu na Androida, dodaj do projektu na Androida zależność wymieniona w Wprowadzenie do WorkManagera.
Z JobService do instancji roboczych
FirebaseJobDispatcher
używa podklasy
JobService
jako punkt wyjścia do określenia działań, które należy wykonać. Możesz być
korzystasz z aplikacji JobService
bezpośrednio lub za pomocą
SimpleJobService
JobService
będzie wyglądać mniej więcej tak:
Kotlin
import com.firebase.jobdispatcher.JobParameters import com.firebase.jobdispatcher.JobService class MyJobService : JobService() { override fun onStartJob(job: JobParameters): Boolean { // Do some work here return false // Answers the question: "Is there still work going on?" } override fun onStopJob(job: JobParameters): Boolean { return false // Answers the question: "Should this job be retried?" } }
Java
import com.firebase.jobdispatcher.JobParameters; import com.firebase.jobdispatcher.JobService; public class MyJobService extends JobService { @Override public boolean onStartJob(JobParameters job) { // Do some work here return false; // Answers the question: "Is there still work going on?" } @Override public boolean onStopJob(JobParameters job) { return false; // Answers the question: "Should this job be retried?" } }
Jeśli używasz wersji SimpleJobService
, zastąpisz wersję onRunJob()
,
, która zwraca typ @JobResult int
.
Główna różnica polega na tym, że gdy używasz bezpośrednio JobService
, onStartJob()
jest wywoływane w wątku głównym i to zadaniem aplikacji jest odciążenie
z wątkiem w tle. Jeśli natomiast używasz
SimpleJobService
, ta usługa jest odpowiedzialna za wykonanie Twojej pracy na
w wątku w tle.
WorkManager ma podobne koncepcje. Podstawową jednostką pracy w usłudze WorkManager jest:
ListenableWorker
. Istnieją
również inne przydatne podtypy instancji roboczych,
Worker
RxWorker
i CoroutineWorker
(gdy
za pomocą współprogramów Kotlin).
Usługa JobService jest mapowana na element ListenableWorker
Jeśli używasz bezpośrednio zasobu JobService
, oznacza to, że instancja robocza, na którą jest mapowana, jest
ListenableWorker
Jeśli korzystasz z SimpleJobService
, użyj
Worker
.
Spójrzmy na przykład powyżej (MyJobService
) i sprawdźmy, jak możemy go przekonwertować.
do: ListenableWorker
.
Kotlin
import android.content.Context import androidx.work.ListenableWorker import androidx.work.ListenableWorker.Result import androidx.work.WorkerParameters import com.google.common.util.concurrent.ListenableFuture class MyWorker(appContext: Context, params: WorkerParameters) : ListenableWorker(appContext, params) { override fun startWork(): ListenableFuture<ListenableWorker.Result> { // Do your work here. TODO("Return a ListenableFuture<Result>") } override fun onStopped() { // Cleanup because you are being stopped. } }
Java
import android.content.Context; import androidx.work.ListenableWorker; import androidx.work.ListenableWorker.Result; import androidx.work.WorkerParameters; import com.google.common.util.concurrent.ListenableFuture; class MyWorker extends ListenableWorker { public MyWorker(@NonNull Context appContext, @NonNull WorkerParameters params) { super(appContext, params); } @Override public ListenableFuture<ListenableWorker.Result> startWork() { // Do your work here. Data input = getInputData(); // Return a ListenableFuture<> } @Override public void onStopped() { // Cleanup because you are being stopped. } }
Podstawową jednostką pracy w usłudze WorkManager jest ListenableWorker
. Tak jak
JobService.onStartJob()
funkcja startWork()
jest wywoływana w wątku głównym. Tutaj
Funkcja MyWorker
implementuje funkcję ListenableWorker
i zwraca instancję
ListenableFuture
,
, który jest używany do asynchronicznego sygnalizowania zakończenia pracy. Wybierz
strategia tworzenia wątków na wątki.
ListenableFuture
w tym miejscu zwraca w końcu typ ListenableWorker.Result
mogą być wartościami Result.success()
, Result.success(Data outputData)
,
Result.retry()
, Result.failure()
lub Result.failure(Data outputData)
. Dla:
więcej informacji można znaleźć na stronie
ListenableWorker.Result
Usługa onStopped()
jest wywoływana, aby zasygnalizować, że ListenableWorker
musi się zatrzymać.
ponieważ ograniczenia nie są już spełnione (na przykład
sieć nie jest już dostępna) lub dlatego, że metoda WorkManager.cancel…()
została
. Pole onStopped()
może być też wywoływane, jeśli system operacyjny zdecyduje się wyłączyć
z jakiegoś powodu.
Usługa SimpleJobService jest mapowana na instancję roboczą
Przy użyciu funkcji SimpleJobService
powyższa instancja robocza będzie wyglądać tak:
Kotlin
import android.content.Context; import androidx.work.Data; import androidx.work.ListenableWorker.Result; import androidx.work.Worker; import androidx.work.WorkerParameters; class MyWorker(context: Context, params: WorkerParameters) : Worker(context, params) { override fun doWork(): Result { TODO("Return a Result") } override fun onStopped() { super.onStopped() TODO("Cleanup, because you are being stopped") } }
Java
import android.content.Context; import androidx.work.Data; import androidx.work.ListenableWorker.Result; import androidx.work.Worker; import androidx.work.WorkerParameters; class MyWorker extends Worker { public MyWorker(@NonNull Context appContext, @NonNull WorkerParameters params) { super(appContext, params); } @Override public Result doWork() { // Do your work here. Data input = getInputData(); // Return a ListenableWorker.Result Data outputData = new Data.Builder() .putString(“Key”, “value”) .build(); return Result.success(outputData); } @Override public void onStopped() { // Cleanup because you are being stopped. } }
W tym miejscu funkcja doWork()
zwraca wystąpienie ciągu ListenableWorker.Result
, aby zasygnalizować działanie
synchronicznie. Jest podobny do harmonogramu SimpleJobService
,
w wątku w tle.
JobBuilder mapuje na WorkRequest
FirebaseJobBuilder używa znaczników Job.Builder
do reprezentowania metadanych Job
. Menedżer roboczy
używa WorkRequest
do wypełniania tej roli.
WorkManager ma 2 typy elementów WorkRequest
:
OneTimeWorkRequest
i
PeriodicWorkRequest
Jeśli korzystasz obecnie z Job.Builder.setRecurring(true)
,
utwórz nowy element: PeriodicWorkRequest
. W przeciwnym razie użyj tagu
OneTimeWorkRequest
Zobaczmy, co może zaplanować wykonanie złożonego zadania Job
z użytkownikiem FirebaseJobDispatcher
wyglądają jak:
Kotlin
val input: Bundle = Bundle().apply { putString("some_key", "some_value") } val job = dispatcher.newJobBuilder() // the JobService that will be called .setService(MyService::class.java) // uniquely identifies the job .setTag("my-unique-tag") // one-off job .setRecurring(false) // don't persist past a device reboot .setLifetime(Lifetime.UNTIL_NEXT_BOOT) // start between 0 and 60 seconds from now .setTrigger(Trigger.executionWindow(0, 60)) // don't overwrite an existing job with the same tag .setReplaceCurrent(false) // retry with exponential backoff .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) .setConstraints( // only run on an unmetered network Constraint.ON_UNMETERED_NETWORK, // // only run when the device is charging Constraint.DEVICE_CHARGING ) .setExtras(input) .build() dispatcher.mustSchedule(job)
Java
Bundle input = new Bundle(); input.putString("some_key", "some_value"); Job myJob = dispatcher.newJobBuilder() // the JobService that will be called .setService(MyJobService.class) // uniquely identifies the job .setTag("my-unique-tag") // one-off job .setRecurring(false) // don't persist past a device reboot .setLifetime(Lifetime.UNTIL_NEXT_BOOT) // start between 0 and 60 seconds from now .setTrigger(Trigger.executionWindow(0, 60)) // don't overwrite an existing job with the same tag .setReplaceCurrent(false) // retry with exponential backoff .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL) // constraints that need to be satisfied for the job to run .setConstraints( // only run on an unmetered network Constraint.ON_UNMETERED_NETWORK, // only run when the device is charging Constraint.DEVICE_CHARGING ) .setExtras(input) .build(); dispatcher.mustSchedule(myJob);
Aby osiągnąć ten sam efekt za pomocą usługi WorkManager:
- Utwórz dane wejściowe, które można wykorzystać jako dane wejściowe dla funkcji
Worker
. - Utwórz element
WorkRequest
z danymi wejściowymi i ograniczeniami podobnymi do tych zdefiniowane powyżej dla zakresuFirebaseJobDispatcher
. - Umieść
WorkRequest
w kolejce.
Konfiguruję dane wejściowe instancji roboczej
Funkcja FirebaseJobDispatcher
używa Bundle
do wysyłania danych wejściowych do funkcji JobService
.
WorkManager używa zamiast niego Data
. No więc
który stanie się:
Kotlin
import androidx.work.workDataOf val data = workDataOf("some_key" to "some_val")
Java
import androidx.work.Data; Data input = new Data.Builder() .putString("some_key", "some_value") .build();
Konfigurowanie ograniczeń dla instancji roboczej
Zastosowania: FirebaseJobDispatcher
Job.Builder.setConstaints(...)
.
aby skonfigurować ograniczenia zadań. WorkManager używa
Constraints
.
Kotlin
import androidx.work.* val constraints: Constraints = Constraints.Builder().apply { setRequiredNetworkType(NetworkType.CONNECTED) setRequiresCharging(true) }.build()
Java
import androidx.work.Constraints; import androidx.work.Constraints.Builder; import androidx.work.NetworkType; Constraints constraints = new Constraints.Builder() // The Worker needs Network connectivity .setRequiredNetworkType(NetworkType.CONNECTED) // Needs the device to be charging .setRequiresCharging(true) .build();
Tworzenie żądania WorkRequest (jednorazowe lub okresowe)
Aby utworzyć elementy OneTimeWorkRequest
i PeriodicWorkRequest
, należy użyć
OneTimeWorkRequest.Builder
.
i PeriodicWorkRequest.Builder
.
Aby utworzyć OneTimeWorkRequest
, który jest podobny do powyższego Job
, musisz
wykonaj te czynności:
Kotlin
import androidx.work.* import java.util.concurrent.TimeUnit val constraints: Constraints = TODO("Define constraints as above") val request: OneTimeWorkRequest = // Tell which work to execute OneTimeWorkRequestBuilder<MyWorker>() // Sets the input data for the ListenableWorker .setInputData(input) // If you want to delay the start of work by 60 seconds .setInitialDelay(60, TimeUnit.SECONDS) // Set a backoff criteria to be used when retry-ing .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 30000, TimeUnit.MILLISECONDS) // Set additional constraints .setConstraints(constraints) .build()
Java
import androidx.work.BackoffCriteria; import androidx.work.Constraints; import androidx.work.Constraints.Builder; import androidx.work.NetworkType; import androidx.work.OneTimeWorkRequest; import androidx.work.OneTimeWorkRequest.Builder; import androidx.work.Data; // Define constraints (as above) Constraints constraints = ... OneTimeWorkRequest request = // Tell which work to execute new OneTimeWorkRequest.Builder(MyWorker.class) // Sets the input data for the ListenableWorker .setInputData(inputData) // If you want to delay the start of work by 60 seconds .setInitialDelay(60, TimeUnit.SECONDS) // Set a backoff criteria to be used when retry-ing .setBackoffCriteria(BackoffCriteria.EXPONENTIAL, 30000, TimeUnit.MILLISECONDS) // Set additional constraints .setConstraints(constraints) .build();
Główna różnica polega na tym, że zadania WorkManagera są zawsze zachowywane gdy urządzenie automatycznie uruchomi się ponownie.
Jeśli chcesz utworzyć element PeriodicWorkRequest
, wykonaj następujące czynności:
Kotlin
val constraints: Constraints = TODO("Define constraints as above") val request: PeriodicWorkRequest = PeriodicWorkRequestBuilder<MyWorker>(15, TimeUnit.MINUTES) // Sets the input data for the ListenableWorker .setInputData(input) // Other setters .build()
Java
import androidx.work.BackoffCriteria; import androidx.work.Constraints; import androidx.work.Constraints.Builder; import androidx.work.NetworkType; import androidx.work.PeriodicWorkRequest; import androidx.work.PeriodicWorkRequest.Builder; import androidx.work.Data; // Define constraints (as above) Constraints constraints = ... PeriodicWorkRequest request = // Executes MyWorker every 15 minutes new PeriodicWorkRequest.Builder(MyWorker.class, 15, TimeUnit.MINUTES) // Sets the input data for the ListenableWorker .setInputData(input) . // other setters (as above) .build();
Planowanie pracy
Po zdefiniowaniu pól Worker
i WorkRequest
możesz przejść do
zaplanować pracę.
Każdy element Job
określony za pomocą funkcji FirebaseJobDispatcher
miał identyfikator tag
, który był używany do
jednoznacznie identyfikować element Job
. Zapewniał też aplikacji
dostęp do informacji,
algorytmu szeregowania, jeśli ta instancja instancji Job
ma zastąpić istniejącą kopię
Job
, dzwoniąc pod numer setReplaceCurrent
.
Kotlin
val job = dispatcher.newJobBuilder() // the JobService that will be called .setService(MyService::class.java) // uniquely identifies the job .setTag("my-unique-tag") // don't overwrite an existing job with the same tag .setRecurring(false) // Other setters... .build()
Java
Job myJob = dispatcher.newJobBuilder() // the JobService that will be called .setService(MyJobService.class) // uniquely identifies the job .setTag("my-unique-tag") // don't overwrite an existing job with the same tag .setReplaceCurrent(false) // other setters // ... dispatcher.mustSchedule(myJob);
Korzystając z WorkManagera, możesz osiągnąć ten sam efekt przy użyciu
Interfejsy API enqueueUniqueWork()
i enqueueUniquePeriodicWork()
(w przypadku korzystania z
OneTimeWorkRequest
i PeriodicWorkRequest
). Więcej
informacje, zapoznaj się ze stronami
WorkManager.enqueueUniqueWork()
i WorkManager.enqueueUniquePeriodicWork()
.
Będzie to wyglądać mniej więcej tak:
Kotlin
import androidx.work.* val request: OneTimeWorkRequest = TODO("A WorkRequest") WorkManager.getInstance(myContext) .enqueueUniqueWork("my-unique-name", ExistingWorkPolicy.KEEP, request)
Java
import androidx.work.ExistingWorkPolicy; import androidx.work.OneTimeWorkRequest; import androidx.work.WorkManager; OneTimeWorkRequest workRequest = // a WorkRequest; WorkManager.getInstance(myContext) // Use ExistingWorkPolicy.REPLACE to cancel and delete any existing pending // (uncompleted) work with the same unique name. Then, insert the newly-specified // work. .enqueueUniqueWork("my-unique-name", ExistingWorkPolicy.KEEP, workRequest);
Anuluję zadanie
W usłudze FirebaseJobDispatcher
możesz anulować pracę, korzystając z tych usług:
Kotlin
dispatcher.cancel("my-unique-tag")
Java
dispatcher.cancel("my-unique-tag");
Korzystając z WorkManagera, możesz:
Kotlin
import androidx.work.WorkManager WorkManager.getInstance(myContext).cancelUniqueWork("my-unique-name")
Java
import androidx.work.WorkManager; WorkManager.getInstance(myContext).cancelUniqueWork("my-unique-name");
Inicjuję WorkManagera
WorkManager zwykle inicjuje się przy użyciu interfejsu ContentProvider
.
Jeśli chcesz mieć większą kontrolę nad sposobem organizacji i harmonogramów WorkManagera,
może dostosować konfigurację i inicjowanie usługi WorkManager.