Android 14 stosuje rygorystyczne reguły, gdy aplikacje mogą korzystać z usług na pierwszym planie.
W Androidzie 14 wprowadzamy też nowy interfejs API, który określa, że zadanie musi być zadaniem transferu danych inicjowanym przez użytkownika. Ten interfejs API jest przydatny w przypadkach, które wymagają dłuższego czasu przesyłania danych inicjowanego przez użytkownika, np. pobierania pliku z serwera zdalnego. Do takich zadań należy wykonać zainicjowane przez użytkownika zadanie transferu danych.
Zadania transferu danych inicjowane przez użytkownika są uruchamiane przez użytkownika. Te zadania wymagają powiadomienia, są uruchamiane natychmiast i mogą być uruchamiane przez dłuższy czas, jeśli zezwalają na to warunki systemowe. Możesz jednocześnie uruchomić kilka zadań przenoszenia danych inicjowanych przez użytkownika.
Zadania inicjowane przez użytkownika muszą być zaplanowane, gdy aplikacja jest widoczna dla użytkownika (lub gdy znajduje się w jednym z dozwolonych warunków). Gdy zostaną spełnione wszystkie ograniczenia, system operacyjny może wykonywać zadania inicjowane przez użytkownika (z uwzględnieniem ograniczeń dotyczących stanu systemu). System może też korzystać z podanego szacowanego rozmiaru ładunku, aby określić czas wykonywania zadania.
Uprawnienia dla zadań transferu danych inicjowanych przez użytkownika
Zadania transferu danych inicjowane przez użytkownika wymagają nowych uprawnień do uruchomienia: RUN_USER_INITIATED_JOBS
. System automatycznie przyznaje to uprawnienie.
Jeśli nie zadeklarujesz uprawnień w manifeście aplikacji, system wygeneruje SecurityException
.
Proces planowania zadań transferu danych inicjowanych przez użytkownika
Aby uruchomić zadanie zainicjowane przez użytkownika, wykonaj te czynności:
Jeśli po raz pierwszy deklarujesz interfejs API w JobScheduler, zadeklarować
JobService
i powiązane uprawnienia w pliku manifestu. Zdefiniuj też konkretną podklasę klasyJobService
na potrzeby przenoszenia danych:<service android:name="com.example.app.CustomTransferService" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="false"> ... </service>
class CustomTransferService : JobService() { ... }
Zadeklaruj w pliku manifestu uprawnienia
RUN_USER_INITIATED_JOBS
:<manifest ...> <uses-permission android:name="android.permission.RUN_USER_INITIATED_JOBS" /> <application ...> ... </application> </manifest>
Wywołaj nową metodę
setUserInitiated()
podczas tworzenia obiektuJobInfo
. Zalecamy też zaoferowanie oszacowania wielkości ładunku wywołując metodęsetEstimatedNetworkBytes()
podczas tworzenia zadania:val networkRequestBuilder = NetworkRequest.Builder() .addCapability(NET_CAPABILITY_INTERNET) .addCapability(NET_CAPABILITY_NOT_METERED) // Add or remove capabilities based on your requirements .build() val jobInfo = JobInfo.Builder() // ... .setUserInitiated(true) .setRequiredNetwork(networkRequestBuilder.build()) .setEstimatedNetworkBytes(1024 * 1024 * 1024) // ... .build()
Zaplanuj zadanie przed rozpoczęciem przenoszenia, podczas gdy w aplikacji jest widoczna lub na liście dozwolonych warunków:
val jobScheduler: JobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler jobScheduler.schedule(jobInfo)
Pamiętaj, aby podczas wykonywania zadania wywołać funkcję
setNotification()
JobService
obiekt. Dzięki tej wartości użytkownik wie, że zadanie jest uruchomiony, zarówno w Menedżerze zadań, jak i w powiadomieniu na pasku stanu. obszar:class CustomTransferService : JobService() { override fun onStartJob(params: JobParameters?): Boolean { val notification = Notification.Builder(applicationContext, NOTIFICATION_CHANNEL_ID) .setContentTitle("My user-initiated data transfer job") .setSmallIcon(android.R.mipmap.myicon) .setContentText("Job is running") .build() setNotification(params, notification.id, notification, JobService.JOB_END_NOTIFICATION_POLICY_DETACH) // Do the job execution. } }
Okresowo aktualizuj powiadomienie, aby informować użytkownika o stanu i postępu. Jeśli nie możesz określić rozmiaru transferu z wyprzedzeniem zaplanować zadanie lub zaktualizować szacowany rozmiar transferu, użyj nowego interfejsu API –
updateEstimatedNetworkBytes()
, aby zaktualizuj rozmiar transferu po jego uzyskaniu.Po zakończeniu wykonywania wywołaj
jobFinished()
, by zasygnalizować system że zadanie zostało ukończone lub należy je przełożyć.
Zadania transferu danych inicjowane przez użytkownika można zatrzymać
Zarówno użytkownik, jak i system mogą zatrzymać zadania transferu zainicjowane przez użytkownika.
Przez użytkownika w Menedżerze zadań
Użytkownik może zatrzymać zainicjowane przez użytkownika zadanie przenoszenia danych widoczne w Menedżerze zadań.
Gdy użytkownik kliknie Zatrzymaj, system wykona te czynności:
- Natychmiast zatrzymuje proces aplikacji, w tym wszystkie uruchomione zadania i usługi na pierwszym planie.
- Nie wywołuje
onStopJob()
w przypadku żadnego uruchomionego zadania. - Zapobiega zmianie harmonogramu zadań widocznych dla użytkowników.
Z tego powodu zalecamy dodanie elementów sterujących w przesłanym powiadomieniu o zadaniu, aby umożliwić płynne zatrzymanie i przełożenie zadania.
Pamiętaj, że w specjalnych okolicznościach przycisk Zatrzymaj nie wyświetla się obok zadania w Menedżerze zadań lub w ogóle nie jest w nim wyświetlane.
System
W przeciwieństwie do zwykłych zadań limity zasobników gotowości aplikacji nie mają wpływu na zadania transferu danych inicjowane przez użytkownika. System zatrzyma jednak zadanie, jeśli wystąpi dowolny z tych warunków:
- Ograniczenie zdefiniowane przez dewelopera nie jest już spełnione.
- System ustala, że zadanie działało dłużej niż jest to konieczne do ukończenia zadania transferu danych.
- System musi traktować priorytetowo stan systemu i zatrzymywać zadania z powodu zwiększonej temperatury.
- Proces aplikacji jest przerywany z powodu zbyt małej ilości pamięci urządzenia.
Gdy zadanie zostanie zatrzymane przez system (a nie w przypadku małej ilości pamięci), system wywoła onStopJob()
, a system ponawia próbę w momencie, gdy system uzna to za optymalne. Sprawdź, czy aplikacja może utrzymywać stan transferu danych, nawet jeśli funkcja onStopJob()
nie jest wywoływana, oraz czy aplikacja może przywrócić ten stan po ponownym wywołaniu funkcji onStartJob()
.
Warunki dozwolone w przypadku planowania zadań transferu danych inicjowanych przez użytkownika
Aplikacje mogą uruchamiać zadanie transferu danych inicjowane przez użytkownika tylko wtedy, gdy jest ona w widocznym oknie lub gdy są spełnione określone warunki. Aby określić, kiedy można zaplanować zadanie przenoszenia danych inicjowane przez użytkownika, system stosuje tę samą listę warunków, które w szczególnych przypadkach pozwalają aplikacjom uruchamiać aktywność w tle. W szczególności ta lista warunków nie jest tym samym co zestaw wykluczeń w przypadku ograniczeń usług działających w tle uruchamianych w tle.
Wyjątki od poprzedniego oświadczenia:
- Jeśli aplikacja może uruchamiać działania w tle, może też uruchamiać w tle inicjowane przez użytkownika zadania przenoszenia danych.
- Jeśli w przypadku aplikacji, która znajduje się w tylnym stosie istniejącego zadania na ekranie Ostatnie, nie można uruchomić zadania przenoszenia danych inicjowanego przez użytkownika.
Jeśli zadanie zostanie zaplanowane w innym czasie, którego nie ma na liście dozwolonych warunków, zadanie nie powiedzie się i zwrócony zostanie kod błędu RESULT_FAILURE
.
Ograniczenia dozwolone w przypadku zadań transferu danych inicjowanych przez użytkownika
Aby ułatwić wykonywanie zadań działających w optymalnych punktach, Android umożliwia przypisywanie ograniczeń do każdego typu zlecenia. Te ograniczenia są już dostępne od wersji Androida 13.
Uwaga: w tabeli poniżej porównano ograniczenia, które różnią się w zależności od typu zadania. Wszystkie ograniczenia znajdziesz na stronie dewelopera JobScheduler lub na stronie o ograniczeniach związanych z pracą.
W tabeli poniżej znajdziesz różne typy zadań, które obsługują określone ograniczenie zadań, a także zestaw ograniczeń zadań obsługiwanych przez WorkManager. Użyj paska wyszukiwania przed tabelą, aby przefiltrować tabelę według nazwy metody ograniczania zadania.
Oto ograniczenia dozwolone w zadaniach przenoszenia danych inicjowanych przez użytkownika:
setBackoffCriteria(JobInfo.BACKOFF_POLICY_EXPONENTIAL)
setClipData()
setEstimatedNetworkBytes()
setMinimumNetworkChunkBytes()
setPersisted()
setNamespace()
setRequiredNetwork()
setRequiredNetworkType()
setRequiresBatteryNotLow()
setRequiresCharging()
setRequiresStorageNotLow()
Testowanie
Na liście poniżej znajdziesz instrukcje ręcznego testowania zadań aplikacji:
- Aby uzyskać identyfikator zadania, pobierz wartość zdefiniowaną przy tworzeniu zadania.
Aby od razu uruchomić zadanie lub ponownie uruchomić zatrzymane zadanie, uruchom następujące polecenie w oknie terminala:
adb shell cmd jobscheduler run -f APP_PACKAGE_NAME JOB_ID
Aby symulować zatrzymanie zadania przez system (ze względu na stan systemu lub w warunkach braku limitu), uruchom to polecenie w oknie terminala:
adb shell cmd jobscheduler timeout TEST_APP_PACKAGE TEST_JOB_ID