WorkManager ma wbudowaną obsługę długotrwałych instancji roboczych. W takich przypadkach WorkManager może przekazać do systemu operacyjnego sygnał, że proces powinien pozostać aktywny jeśli jest to możliwe podczas ich wykonywania. Te instancje robocze mogą działać dłużej niż 10 min. Przykładowe zastosowania tej nowej funkcji obejmują przesyłanie zbiorcze lub pobrane pliki (które nie mogą zostać podzielone na fragmenty), lokalne crunching w modelu ML lub zadanie które są ważne dla użytkownika aplikacji.
WorkManager zarządza usługą na pierwszym planie i uruchamia ją w Twoim imieniu
do wykonania polecenia WorkRequest
oraz wyświetlam
powiadomienia.
ListenableWorker
obsługuje teraz interfejs API setForegroundAsync()
oraz
CoroutineWorker
obsługuje interfejs API zawieszania setForeground()
. Te
Interfejsy API pozwalają programistom określić, że WorkRequest
jest ważny (z
z perspektywy użytkownika) lub długotrwałe.
Od 2.3.0-alpha03
WorkManager umożliwia też tworzenie
PendingIntent
– za pomocą tej funkcji można anulować instancje robocze bez konieczności
zarejestruj nowy komponent Androida za pomocą createCancelPendingIntent()
API. Ta metoda jest szczególnie przydatna, gdy
interfejsów API setForegroundAsync()
lub setForeground()
, których można użyć do dodania
powiadomienie, aby anulować Worker
.
Tworzenie długotrwałych instancji roboczych i zarządzanie nimi
Użyjesz nieco innego podejścia w zależności od tego, czy kodujesz Kotlin lub Java.
Kotlin
Programiści z Kotlin powinni używać narzędzia CoroutineWorker
. Zamiast użycia
setForegroundAsync()
, możesz użyć zawieszającej wersji tej metody,
setForeground()
class DownloadWorker(context: Context, parameters: WorkerParameters) :
CoroutineWorker(context, parameters) {
private val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as
NotificationManager
override suspend fun doWork(): Result {
val inputUrl = inputData.getString(KEY_INPUT_URL)
?: return Result.failure()
val outputFile = inputData.getString(KEY_OUTPUT_FILE_NAME)
?: return Result.failure()
// Mark the Worker as important
val progress = "Starting Download"
setForeground(createForegroundInfo(progress))
download(inputUrl, outputFile)
return Result.success()
}
private fun download(inputUrl: String, outputFile: String) {
// Downloads a file and updates bytes read
// Calls setForeground() periodically when it needs to update
// the ongoing Notification
}
// Creates an instance of ForegroundInfo which can be used to update the
// ongoing notification.
private fun createForegroundInfo(progress: String): ForegroundInfo {
val id = applicationContext.getString(R.string.notification_channel_id)
val title = applicationContext.getString(R.string.notification_title)
val cancel = applicationContext.getString(R.string.cancel_download)
// This PendingIntent can be used to cancel the worker
val intent = WorkManager.getInstance(applicationContext)
.createCancelPendingIntent(getId())
// Create a Notification channel if necessary
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createChannel()
}
val notification = NotificationCompat.Builder(applicationContext, id)
.setContentTitle(title)
.setTicker(title)
.setContentText(progress)
.setSmallIcon(R.drawable.ic_work_notification)
.setOngoing(true)
// Add the cancel action to the notification which can
// be used to cancel the worker
.addAction(android.R.drawable.ic_delete, cancel, intent)
.build()
return ForegroundInfo(notificationId, notification)
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createChannel() {
// Create a Notification channel
}
companion object {
const val KEY_INPUT_URL = "KEY_INPUT_URL"
const val KEY_OUTPUT_FILE_NAME = "KEY_OUTPUT_FILE_NAME"
}
}
Java
Deweloperzy używający interfejsu ListenableWorker
lub Worker
mogą wywoływać metodę
Interfejs API setForegroundAsync()
, który zwraca ListenableFuture<Void>
. Ty
może również wywołać funkcję setForegroundAsync()
, aby zaktualizować trwające Notification
.
Oto prosty przykład długotrwałej instancji roboczej, która pobiera plik. Ten
Instancja robocza śledzi postęp w aktualizacji trwającego Notification
, które pokazuje
postęp pobierania.
public class DownloadWorker extends Worker {
private static final String KEY_INPUT_URL = "KEY_INPUT_URL";
private static final String KEY_OUTPUT_FILE_NAME = "KEY_OUTPUT_FILE_NAME";
private NotificationManager notificationManager;
public DownloadWorker(
@NonNull Context context,
@NonNull WorkerParameters parameters) {
super(context, parameters);
notificationManager = (NotificationManager)
context.getSystemService(NOTIFICATION_SERVICE);
}
@NonNull
@Override
public Result doWork() {
Data inputData = getInputData();
String inputUrl = inputData.getString(KEY_INPUT_URL);
String outputFile = inputData.getString(KEY_OUTPUT_FILE_NAME);
// Mark the Worker as important
String progress = "Starting Download";
setForegroundAsync(createForegroundInfo(progress));
download(inputUrl, outputFile);
return Result.success();
}
private void download(String inputUrl, String outputFile) {
// Downloads a file and updates bytes read
// Calls setForegroundAsync(createForegroundInfo(myProgress))
// periodically when it needs to update the ongoing Notification.
}
@NonNull
private ForegroundInfo createForegroundInfo(@NonNull String progress) {
// Build a notification using bytesRead and contentLength
Context context = getApplicationContext();
String id = context.getString(R.string.notification_channel_id);
String title = context.getString(R.string.notification_title);
String cancel = context.getString(R.string.cancel_download);
// This PendingIntent can be used to cancel the worker
PendingIntent intent = WorkManager.getInstance(context)
.createCancelPendingIntent(getId());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createChannel();
}
Notification notification = new NotificationCompat.Builder(context, id)
.setContentTitle(title)
.setTicker(title)
.setSmallIcon(R.drawable.ic_work_notification)
.setOngoing(true)
// Add the cancel action to the notification which can
// be used to cancel the worker
.addAction(android.R.drawable.ic_delete, cancel, intent)
.build();
return new ForegroundInfo(notificationId, notification);
}
@RequiresApi(Build.VERSION_CODES.O)
private void createChannel() {
// Create a Notification channel
}
}
Dodawanie typu usługi na pierwszym planie do długotrwałej instancji roboczej
Jeśli Twoja aplikacja jest kierowana na Androida 14 (poziom interfejsu API 34) lub nowszego, musisz określić
typ usługi na pierwszym planie dla wszystkich długotrwałych instancji roboczych.
Jeśli aplikacja jest kierowana na Androida 10 (poziom interfejsu API 29) lub nowszego i zawiera
długotrwała instancja robocza, która wymaga dostępu do lokalizacji, wskaż, że instancja robocza
korzysta z typu usługi na pierwszym planie: location
.
Jeśli Twoja aplikacja jest kierowana na Androida 11 (poziom interfejsu API 30) lub nowszego
i zawiera długoterminową instancję roboczą, która wymaga dostępu do kamery lub mikrofonu.
zadeklaruj pierwszy plan działania camera
lub microphone
typy usług.
Aby dodać te typy usług na pierwszym planie, wykonaj czynności opisane w poniższych sekcji.
Deklarowanie typów usług na pierwszym planie w manifeście aplikacji
Zadeklaruj typ usługi na pierwszym planie instancji roboczej w pliku manifestu aplikacji. W W tym przykładzie instancja robocza wymaga dostępu do lokalizacji i mikrofonu:
<service android:name="androidx.work.impl.foreground.SystemForegroundService" android:foregroundServiceType="location|microphone" tools:node="merge" />
Określ typy usług na pierwszym planie w czasie działania
Gdy dzwonisz pod numer setForeground()
lub setForegroundAsync()
, podaj
typu usługi na pierwszym planie.
Kotlin
private fun createForegroundInfo(progress: String): ForegroundInfo { // ... return ForegroundInfo(NOTIFICATION_ID, notification, FOREGROUND_SERVICE_TYPE_LOCATION or FOREGROUND_SERVICE_TYPE_MICROPHONE) }
Java
@NonNull private ForegroundInfo createForegroundInfo(@NonNull String progress) { // Build a notification... Notification notification = ...; return new ForegroundInfo(NOTIFICATION_ID, notification, FOREGROUND_SERVICE_TYPE_LOCATION | FOREGROUND_SERVICE_TYPE_MICROPHONE); }