Questo codelab fa parte del corso Android Kotlin Fundamentals. Per ottenere il massimo valore da questo corso, ti consigliamo di seguire le codelab in sequenza. Tutti i codelab del corso sono elencati nella pagina di destinazione dei codelab Android Kotlin Fundamentals.
Introduzione
La maggior parte delle app reali deve eseguire attività in background di lunga durata. Ad esempio, un'app potrebbe caricare file su un server, sincronizzare i dati da un server e salvarli in un database Room
, inviare log a un server o eseguire operazioni costose sui dati. Queste operazioni devono essere eseguite in background, al di fuori del thread UI (thread principale). Le attività in background consumano le risorse limitate di un dispositivo, come RAM e batteria. Se non viene gestita correttamente, l'esperienza utente potrebbe essere negativa.
In questo codelab, imparerai a utilizzare WorkManager
per pianificare un'attività in background in modo ottimizzato ed efficiente. Per scoprire di più su altre soluzioni disponibili per l'elaborazione in background su Android, consulta la Guida all'elaborazione in background.
Cosa devi già sapere
- Come utilizzare i componenti dell'architettura Android
ViewModel
,LiveData
eRoom
. - Come eseguire le trasformazioni su una classe
LiveData
. - Come creare e avviare una coroutine.
- Come utilizzare gli adattatori di binding nel data binding.
- Come caricare i dati memorizzati nella cache utilizzando un pattern del repository.
Obiettivi didattici
- Come creare un
Worker
, che rappresenta un'unità di lavoro. - Come creare un
WorkRequest
per richiedere l'esecuzione di un lavoro. - Come aggiungere vincoli a
WorkRequest
per definire come e quando deve essere eseguito un worker. - Come utilizzare
WorkManager
per pianificare le attività in background.
In questo lab proverai a:
- Crea un worker per eseguire un'attività in background per precaricare la playlist di video DevBytes dalla rete.
- Pianifica l'esecuzione periodica del worker.
- Aggiungi vincoli a
WorkRequest
. - Pianifica un
WorkRequest
periodico che viene eseguito una volta al giorno.
In questo codelab, lavorerai sull'app DevBytes che hai sviluppato in un codelab precedente. Se non hai questa app, puoi scaricare il codice iniziale per questa lezione.
L'app DevBytes mostra un elenco di video DevByte, brevi tutorial realizzati dal team di relazioni con gli sviluppatori di Google Android. I video presentano le funzionalità per sviluppatori e le best practice per lo sviluppo di Android.
Migliori l'esperienza utente nell'app precaricando i video una volta al giorno. In questo modo, l'utente riceve contenuti aggiornati non appena apre l'app.
In questa attività scaricherai ed esaminerai il codice iniziale.
Passaggio 1: scarica ed esegui l'app iniziale
Puoi continuare a lavorare con l'app DevBytes che hai creato nel codelab precedente (se ce l'hai). In alternativa, puoi scaricare l'app iniziale.
In questa attività scaricherai ed eseguirai l'app iniziale ed esaminerai il codice iniziale.
- Se non hai ancora l'app DevBytes, scarica il codice iniziale di DevBytes per questo codelab dal progetto DevBytesRepository da GitHub.
- Decomprimi il codice e apri il progetto in Android Studio.
- Connetti il dispositivo di test o l'emulatore a internet, se non è già connesso. Crea ed esegui l'app. L'app recupera l'elenco dei video di DevBytes dalla rete e li visualizza.
- Nell'app, tocca un video per aprirlo nell'app YouTube.
Passaggio 2: esplora il codice
L'app iniziale include molto codice introdotto nel codelab precedente. Il codice iniziale di questo codelab include i moduli di rete, interfaccia utente, cache offline e repository. Puoi concentrarti sulla pianificazione dell'attività in background utilizzando WorkManager
.
- In Android Studio, espandi tutti i pacchetti.
- Esplora il pacchetto
database
. Il pacchetto contiene le entità del database e il database locale, implementato utilizzandoRoom
. - Esplora il pacchetto
repository
. Il pacchetto contiene la classeVideosRepository
che astrae il livello dati dal resto dell'app. - Esplora il resto del codice iniziale in autonomia e con l'aiuto del codelab precedente.
WorkManager
è uno dei componenti dell'architettura Android e fa parte di Android Jetpack. WorkManager
è per il lavoro in background rinviabile che richiede l'esecuzione garantita:
- Differibile significa che il lavoro non deve essere eseguito immediatamente. Ad esempio, l'invio di dati analitici al server o la sincronizzazione del database in background sono attività che possono essere posticipate.
- Esecuzione garantita significa che l'attività verrà eseguita anche se l'app si chiude o il dispositivo si riavvia.
Mentre WorkManager
esegue il lavoro in background, si occupa dei problemi di compatibilità e delle best practice per la batteria e l'integrità del sistema. WorkManager
offre la compatibilità fino al livello API 14. WorkManager
sceglie un modo appropriato per pianificare un'attività in background, a seconda del livello API del dispositivo. Potrebbe utilizzare JobScheduler
(su API 23 e successive) o una combinazione di AlarmManager
e BroadcastReceiver
.
WorkManager
ti consente anche di impostare i criteri per l'esecuzione dell'attività in background. Ad esempio, potresti voler eseguire l'attività solo quando lo stato della batteria, lo stato della rete o lo stato di carica soddisfano determinati criteri. Imparerai a impostare i vincoli più avanti in questo codelab.
In questo codelab, pianifichi un'attività per precaricare la playlist di video DevBytes dalla rete una volta al giorno. Per pianificare questa attività, utilizzi la libreria WorkManager
.
- Apri il file
build.gradle (Module:app)
e aggiungi la dipendenzaWorkManager
al progetto.
Se utilizzi l'ultima versione della libreria, la compilazione dell'app di soluzione dovrebbe avvenire come previsto. In caso contrario, prova a risolvere il problema o ripristina la versione della libreria mostrata di seguito.
// WorkManager dependency
def work_version = "1.0.1"
implementation "android.arch.work:work-runtime-ktx:$work_version"
- Sincronizza il progetto e assicurati che non siano presenti errori di compilazione.
Prima di aggiungere codice al progetto, acquisisci familiarità con le seguenti classi nella libreria WorkManager
:
Worker
Questa classe definisce il lavoro effettivo (l'attività) da eseguire in background. Estendi questa classe e sostituisci il metododoWork()
. Il metododoWork()
è quello in cui inserisci il codice da eseguire in background, ad esempio la sincronizzazione dei dati con il server o l'elaborazione delle immagini. In questa attività implementeraiWorker
.WorkRequest
Questa classe rappresenta una richiesta di esecuzione del worker in background. UtilizzaWorkRequest
per configurare come e quando eseguire l'attività worker, con l'aiuto diConstraints
come il dispositivo collegato o la connessione Wi-Fi. ImplementeraiWorkRequest
in un'attività successiva.WorkManager
Questa classe pianifica ed esegue il tuoWorkRequest
.WorkManager
pianifica le richieste di lavoro in modo da distribuire il carico sulle risorse di sistema, rispettando i vincoli specificati. ImplementeraiWorkManager
in un'attività successiva.
Passaggio 1: crea un lavoratore
In questa attività, aggiungi un Worker
per precaricare in background la playlist di video DevBytes.
- All'interno del pacchetto
devbyteviewer
, crea un nuovo pacchetto denominatowork
. - All'interno del pacchetto
work
, crea una nuova classe Kotlin denominataRefreshDataWorker
. - Estendi il corso
RefreshDataWorker
dal corsoCoroutineWorker
. Inseriscicontext
eWorkerParameters
come parametri del costruttore.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
CoroutineWorker(appContext, params) {
}
- Per risolvere l'errore della classe astratta, esegui l'override del metodo
doWork()
all'interno della classeRefreshDataWorker
.
override suspend fun doWork(): Result {
return Result.success()
}
Una funzione di sospensione è una funzione che può essere sospesa e ripresa in un secondo momento. Una funzione di sospensione può eseguire un'operazione a esecuzione prolungata e attendere il completamento senza bloccare il thread principale.
Passaggio 2: implementa doWork()
Il metodo doWork()
all'interno della classe Worker
viene chiamato su un thread in background. Il metodo esegue il lavoro in modo sincrono e deve restituire un oggetto ListenableWorker.Result
. Il sistema Android concede a un Worker
un massimo di 10 minuti per completare l'esecuzione e restituire un oggetto ListenableWorker.Result
. Trascorso questo periodo di tempo, il sistema interrompe forzatamente Worker
.
Per creare un oggetto ListenableWorker.Result
, chiama uno dei seguenti metodi statici per indicare lo stato di completamento del lavoro in background:
Result.success()
: il lavoro è stato completato correttamente.Result.failure()
: il lavoro è stato completato con un errore permanente.Result.retry()
: il lavoro ha riscontrato un errore temporaneo e deve essere ritentato.
In questa attività implementerai il metodo doWork()
per recuperare la playlist di video DevBytes dalla rete. Puoi riutilizzare i metodi esistenti nella classe VideosRepository
per recuperare i dati dalla rete.
- Nella classe
RefreshDataWorker
, all'interno didoWork()
, crea e istanzia un oggettoVideosDatabase
e un oggettoVideosRepository
.
override suspend fun doWork(): Result {
val database = getDatabase(applicationContext)
val repository = VideosRepository(database)
return Result.success()
}
- Nella classe
RefreshDataWorker
, all'interno didoWork()
, sopra l'istruzionereturn
, chiama il metodorefreshVideos()
all'interno di un bloccotry
. Aggiungi un log per monitorare quando viene eseguito il worker.
try {
repository.refreshVideos( )
Timber.d("Work request for sync is run")
} catch (e: HttpException) {
return Result.retry()
}
Per risolvere l'errore "Riferimento non risolto", importa retrofit2.HttpException
.
- Ecco la classe
RefreshDataWorker
completa per riferimento:
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
CoroutineWorker(appContext, params) {
override suspend fun doWork(): Result {
val database = getDatabase(applicationContext)
val repository = VideosRepository(database)
try {
repository.refreshVideos()
} catch (e: HttpException) {
return Result.retry()
}
return Result.success()
}
}
Un Worker
definisce un'unità di lavoro e il WorkRequest
definisce come e quando deve essere eseguito il lavoro. Esistono due implementazioni concrete della classe WorkRequest
:
- Il corso
OneTimeWorkRequest
è per le attività una tantum. Un'attività una tantum viene eseguita una sola volta. - Il corso
PeriodicWorkRequest
è destinato a lavori periodici, che si ripetono a intervalli.
Le attività possono essere una tantum o periodiche, quindi scegli il corso di conseguenza. Per saperne di più sulla pianificazione del lavoro ricorrente, consulta la documentazione sul lavoro ricorrente.
In questa attività, definisci e pianifichi un WorkRequest
per eseguire il worker che hai creato nell'attività precedente.
Passaggio 1: configura il lavoro ricorrente
All'interno di un'app per Android, la classe Application
è la classe base che contiene tutti gli altri componenti, come attività e servizi. Quando viene creato il processo per l'applicazione o il pacchetto, la classe Application
(o qualsiasi sottoclasse di Application
) viene istanziata prima di qualsiasi altra classe.
In questa app di esempio, la classe DevByteApplication
è una sottoclasse della classe Application
. La lezione di DevByteApplication
è un buon momento per programmare la WorkManager
.
- Nella classe
DevByteApplication
, crea un metodo chiamatosetupRecurringWork()
per configurare il lavoro in background ricorrente.
/**
* Setup WorkManager background job to 'fetch' new network data daily.
*/
private fun setupRecurringWork() {
}
- All'interno del metodo
setupRecurringWork()
, crea e inizializza una richiesta di lavoro periodica da eseguire una volta al giorno utilizzando il metodoPeriodicWorkRequestBuilder()
. Inserisci la classeRefreshDataWorker
che hai creato nell'attività precedente. Passa un intervallo di ripetizione di1
con un'unità di tempo diTimeUnit.
DAYS
.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
.build()
Per risolvere l'errore, importa java.util.concurrent.TimeUnit
.
Passaggio 2: pianifica una WorkRequest con WorkManager
Dopo aver definito il WorkRequest
, puoi pianificarlo con WorkManager
utilizzando il metodo enqueueUniquePeriodicWork()
. Questo metodo consente di aggiungere alla coda un PeriodicWorkRequest
con un nome univoco, in cui può essere attivo un solo PeriodicWorkRequest
con un determinato nome alla volta.
Ad esempio, potresti voler attivare una sola operazione di sincronizzazione. Se un'operazione di sincronizzazione è in attesa, puoi scegliere di eseguirla o sostituirla con il tuo nuovo lavoro utilizzando un ExistingPeriodicWorkPolicy.
Per scoprire di più sui modi per pianificare un WorkRequest
, consulta la documentazione di WorkManager
.
- Nella classe
RefreshDataWorker
, all'inizio della classe, aggiungi un oggetto complementare. Definisci un nome del worker per identificarlo in modo univoco.
companion object {
const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}
- Nella classe
DevByteApplication
, alla fine del metodosetupRecurringWork()
, pianifica il lavoro utilizzando il metodoenqueueUniquePeriodicWork()
. Passa l'enumerazioneKEEP
per ExistingPeriodicWorkPolicy. InseriscirepeatingRequest
come parametroPeriodicWorkRequest
.
WorkManager.getInstance().enqueueUniquePeriodicWork(
RefreshDataWorker.WORK_NAME,
ExistingPeriodicWorkPolicy.KEEP,
repeatingRequest)
Se esiste un lavoro in attesa (non completato) con lo stesso nome, il parametro ExistingPeriodicWorkPolicy.
KEEP
fa sì che WorkManager
mantenga il lavoro periodico precedente e scarti la nuova richiesta di lavoro.
- All'inizio della classe
DevByteApplication
, crea un oggettoCoroutineScope
. InserisciDispatchers.Default
come parametro del costruttore.
private val applicationScope = CoroutineScope(Dispatchers.Default)
- Nella classe
DevByteApplication
, aggiungi un nuovo metodo chiamatodelayedInit()
per avviare una coroutine.
private fun delayedInit() {
applicationScope.launch {
}
}
- All'interno del metodo
delayedInit()
, chiamasetupRecurringWork()
. - Sposta l'inizializzazione di Timber dal metodo
onCreate()
al metododelayedInit()
.
private fun delayedInit() {
applicationScope.launch {
Timber.plant(Timber.DebugTree())
setupRecurringWork()
}
}
- Nella classe
DevByteApplication
, alla fine del metodoonCreate()
, aggiungi una chiamata al metododelayedInit()
.
override fun onCreate() {
super.onCreate()
delayedInit()
}
- Apri il riquadro Logcat nella parte inferiore della finestra di Android Studio. Filtra in base a
RefreshDataWorker
. - Esegui l'app.
WorkManager
pianifica immediatamente il lavoro ricorrente.
Nel riquadro Logcat, nota le istruzioni di log che mostrano che la richiesta di lavoro è pianificata e poi viene eseguita correttamente.
D/RefreshDataWorker: Work request for sync is run I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
Il log WM-WorkerWrapper
viene visualizzato dalla libreria WorkManager
, quindi non puoi modificare questo messaggio di log.
Passaggio 3: (facoltativo) pianifica la richiesta di lavoro per un intervallo minimo
In questo passaggio, riduci l'intervallo di tempo da 1 giorno a 15 minuti. In questo modo, puoi vedere i log di una richiesta di lavoro periodica in azione.
- Nella classe
DevByteApplication
, all'interno del metodosetupRecurringWork()
, commenta la definizione corrente direpeatingRequest
. Aggiungi una nuova richiesta di lavoro con un intervallo di ripetizione periodica di15
minuti.
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
// .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
.build()
- Apri il riquadro Logcat in Android Studio e filtra in base a
RefreshDataWorker
. Per cancellare i log precedenti, fai clic sull'icona Cancella logcat.
- Esegui l'app e
WorkManager
pianifica immediatamente il lavoro ricorrente. Nel riquadro Logcat, nota i log: la richiesta di lavoro viene eseguita una volta ogni 15 minuti. Attendi 15 minuti per visualizzare un altro insieme di log delle richieste di lavoro. Puoi lasciare l'app in esecuzione o chiuderla; il gestore delle attività dovrebbe comunque essere in esecuzione.
Tieni presente che l'intervallo a volte è inferiore a 15 minuti e a volte superiore a 15 minuti. (La tempistica esatta è soggetta alle ottimizzazioni della batteria del sistema operativo).
12:44:40 D/RefreshDataWorker: Work request for sync is run 12:44:40 I/WM-WorkerWrapper: Worker result SUCCESS for Work 12:59:24 D/RefreshDataWorker: Work request for sync is run 12:59:24 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:15:03 D/RefreshDataWorker: Work request for sync is run 13:15:03 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:29:22 D/RefreshDataWorker: Work request for sync is run 13:29:22 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:44:26 D/RefreshDataWorker: Work request for sync is run 13:44:26 I/WM-WorkerWrapper: Worker result SUCCESS for Work
Complimenti! Hai creato un lavoratore e pianificato la richiesta di lavoro con WorkManager
. Ma c'è un problema: non hai specificato alcun vincolo. WorkManager
pianificherà il lavoro una volta al giorno, anche se la batteria del dispositivo è in esaurimento, il dispositivo è in modalità Sospensione o non è connesso a una rete. Ciò influirà sulla batteria e sulle prestazioni del dispositivo e potrebbe comportare un'esperienza utente scadente.
Nell'attività successiva, risolverai questo problema aggiungendo vincoli.
Nell'attività precedente, hai utilizzato WorkManager
per pianificare una richiesta di lavoro. In questa attività aggiungi i criteri per l'esecuzione del lavoro.
Quando definisci WorkRequest
, puoi specificare i vincoli per il momento in cui deve essere eseguito Worker
. Ad esempio, potresti voler specificare che l'attività deve essere eseguita solo quando il dispositivo è inattivo o solo quando è collegato e connesso alla rete Wi-Fi. Puoi anche specificare una policy di backoff per riprovare a eseguire il lavoro. I vincoli supportati sono i metodi impostati in Constraints.Builder
. Per scoprire di più, consulta Definire le richieste di lavoro.
Passaggio 1: aggiungi un oggetto Constraints e imposta un vincolo
In questo passaggio, crei un oggetto Constraints
e imposti un vincolo sull'oggetto, un vincolo di tipo di rete. È più facile notare i log con un solo vincolo. In un passaggio successivo, aggiungi altri vincoli.)
- Nella classe
DevByteApplication
, all'inizio disetupRecurringWork()
, definisci unval
di tipoConstraints
. Utilizza il metodoConstraints.Builder()
.
val constraints = Constraints.Builder()
Per risolvere l'errore, importa androidx.work.Constraints
.
- Utilizza il metodo
setRequiredNetworkType()
per aggiungere un vincolo di tipo rete all'oggettoconstraints
. Utilizza l'enumerazioneUNMETERED
in modo che la richiesta di lavoro venga eseguita solo quando il dispositivo è connesso a una rete non a consumo.
.setRequiredNetworkType(NetworkType.UNMETERED)
- Utilizza il metodo
build()
per generare i vincoli dal generatore.
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.build()
Ora devi impostare l'oggetto Constraints
appena creato sulla richiesta di lavoro.
- Nella classe
DevByteApplication
, all'interno del metodosetupRecurringWork()
, imposta l'oggettoConstraints
sulla richiesta di lavoro periodica,repeatingRequest
. Per impostare i vincoli, aggiungi il metodosetConstraints()
sopra la chiamata al metodobuild()
.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
.setConstraints(constraints)
.build()
Passaggio 2: esegui l'app e prendi nota dei log
In questo passaggio, esegui l'app e noti che la richiesta di lavoro vincolata viene eseguita in background a intervalli.
- Disinstalla l'app dal dispositivo o dall'emulatore per annullare le attività pianificate in precedenza.
- Apri il riquadro Logcat in Android Studio. Nel riquadro Logcat, cancella i log precedenti facendo clic sull'icona Cancella logcat
a sinistra. Filtra in base a
work
. - Disattiva il Wi-Fi nel dispositivo o nell'emulatore per vedere come funzionano i vincoli. Il codice attuale imposta un solo vincolo, indicando che la richiesta deve essere eseguita solo su una rete senza limiti. Poiché il Wi-Fi è disattivato, il dispositivo non è connesso alla rete, a consumo o senza limiti. Pertanto, questo vincolo non verrà soddisfatto.
- Esegui l'app e nota il riquadro Logcat.
WorkManager
pianifica immediatamente l'attività in background. Poiché il vincolo di rete non è soddisfatto, l'attività non viene eseguita.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
- Attiva il Wi-Fi nel dispositivo o nell'emulatore e guarda il riquadro Logcat. Ora l'attività in background pianificata viene eseguita circa ogni 15 minuti, a condizione che il vincolo di rete sia soddisfatto.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled 11:31:47 D/RefreshDataWorker: Work request for sync is run 11:31:47 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 11:46:45 D/RefreshDataWorker: Work request for sync is run 11:46:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:03:05 D/RefreshDataWorker: Work request for sync is run 12:03:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:16:45 D/RefreshDataWorker: Work request for sync is run 12:16:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:31:45 D/RefreshDataWorker: Work request for sync is run 12:31:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:47:05 D/RefreshDataWorker: Work request for sync is run 12:47:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 13:01:45 D/RefreshDataWorker: Work request for sync is run 13:01:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
Passaggio 3: aggiungi altri vincoli
In questo passaggio, aggiungi i seguenti vincoli a PeriodicWorkRequest
:
- Batteria non scarica.
- Ricarica del dispositivo.
- Dispositivo inattivo; disponibile solo nel livello API 23 (Android M) e versioni successive.
Implementa quanto segue nella classe DevByteApplication
.
- Nella classe
DevByteApplication
, all'interno del metodosetupRecurringWork()
, indica che la richiesta di lavoro deve essere eseguita solo se la batteria non è in esaurimento. Aggiungi il vincolo prima della chiamata al metodobuild()
e utilizza il metodosetRequiresBatteryNotLow()
.
.setRequiresBatteryNotLow(true)
- Aggiorna la richiesta di lavoro in modo che venga eseguita solo quando il dispositivo è in carica. Aggiungi il vincolo prima della chiamata al metodo
build()
e utilizza il metodosetRequiresCharging()
.
.setRequiresCharging(true)
- Aggiorna la richiesta di lavoro in modo che venga eseguita solo quando il dispositivo è inattivo. Aggiungi il vincolo prima della chiamata al metodo
build()
e utilizza il metodosetRequiresDeviceIdle()
. Questo vincolo esegue la richiesta di lavoro solo quando l'utente non sta utilizzando attivamente il dispositivo. Questa funzionalità è disponibile solo in Android 6.0 (Marshmallow) e versioni successive, quindi aggiungi una condizione per la versione SDKM
e successive.
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(true)
}
}
Ecco la definizione completa dell'oggetto constraints
.
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true)
.setRequiresCharging(true)
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(true)
}
}
.build()
- All'interno del metodo
setupRecurringWork()
, modifica l'intervallo di richiesta in una volta al giorno.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
.setConstraints(constraints)
.build()
Ecco l'implementazione completa del metodo setupRecurringWork()
, con un log per monitorare la pianificazione della richiesta di lavoro periodica.
private fun setupRecurringWork() {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true)
.setRequiresCharging(true)
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(true)
}
}
.build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
.setConstraints(constraints)
.build()
Timber.d("Periodic Work request for sync is scheduled")
WorkManager.getInstance().enqueueUniquePeriodicWork(
RefreshDataWorker.WORK_NAME,
ExistingPeriodicWorkPolicy.KEEP,
repeatingRequest)
}
- Per rimuovere la richiesta di lavoro pianificata in precedenza, disinstalla l'app DevBytes dal dispositivo o dall'emulatore.
- Esegui l'app e
WorkManager
pianifica immediatamente la richiesta di lavoro. La richiesta di lavoro viene eseguita una volta al giorno, quando vengono soddisfatti tutti i vincoli. - Questa richiesta di lavoro verrà eseguita in background finché l'app è installata, anche se non è in esecuzione. Per questo motivo, devi disinstallare l'app dallo smartphone.
Ottimo lavoro! Hai implementato e pianificato una richiesta di lavoro a basso consumo di batteria per il precaricamento giornaliero dei video nell'app DevBytes. WorkManager
pianificherà ed eseguirà il lavoro, ottimizzando le risorse di sistema. I tuoi utenti e le loro batterie saranno molto felici.
Progetto Android Studio: DevBytesWorkManager.
- L'API
WorkManager
semplifica la pianificazione di attività asincrone differibili che devono essere eseguite in modo affidabile. - La maggior parte delle app reali deve eseguire attività in background di lunga durata. Per pianificare un'attività in background in modo ottimizzato ed efficiente, utilizza
WorkManager
. - Le classi principali della libreria
WorkManager
sonoWorker
,WorkRequest
eWorkManager
. - La classe
Worker
rappresenta un'unità di lavoro. Per implementare l'attività in background, estendi la classeWorker
e sostituisci il metododoWork()
. - La classe
WorkRequest
rappresenta una richiesta di esecuzione di un'unità di lavoro.WorkRequest
è la classe base per specificare i parametri per il lavoro che pianifichi inWorkManager
. - Esistono due implementazioni concrete della classe
WorkRequest
:OneTimeWorkRequest
per le attività una tantum ePeriodicWorkRequest
per le richieste di lavoro periodiche. - Quando definisci
WorkRequest
, puoi specificareConstraints
che indica quando deve essere eseguitoWorker
. I vincoli includono elementi come se il dispositivo è collegato alla corrente, se è inattivo o se è connesso al Wi-Fi. - Per aggiungere vincoli a
WorkRequest
, utilizza i metodi di impostazione elencati nella documentazione diConstraints.Builder
. Ad esempio, per indicare cheWorkRequest
non deve essere eseguito se la batteria del dispositivo è scarica, utilizza il metodo setsetRequiresBatteryNotLow()
. - Dopo aver definito l'
WorkRequest
, delega l'attività al sistema Android. Per farlo, pianifica l'attività utilizzando uno deiWorkManager
metodienqueue
. - L'ora esatta in cui viene eseguito il
Worker
dipende dai vincoli utilizzati nelWorkRequest
e dalle ottimizzazioni del sistema.WorkManager
è progettato per offrire il miglior comportamento possibile, tenendo conto di queste limitazioni.
Corso Udacity:
Documentazione per sviluppatori Android:
- Definizione delle richieste di lavoro
WorkManager
- Inizia a utilizzare WorkManager
- Lavoro ricorrente
- Guida all'elaborazione in background
Altro:
Questa sezione elenca i possibili compiti a casa per gli studenti che seguono questo codelab nell'ambito di un corso guidato da un insegnante. Spetta all'insegnante:
- Assegna i compiti, se richiesto.
- Comunica agli studenti come inviare i compiti.
- Valuta i compiti a casa.
Gli insegnanti possono utilizzare questi suggerimenti nella misura che ritengono opportuna e sono liberi di assegnare qualsiasi altro compito a casa che ritengono appropriato.
Se stai seguendo questo codelab in autonomia, sentiti libero di utilizzare questi compiti per casa per mettere alla prova le tue conoscenze.
Domanda 1
Quali sono le implementazioni concrete della classe WorkRequest
?
▢ OneTimeWorkPeriodicRequest
▢ OneTimeWorkRequest
e PeriodicWorkRequest
▢ OneTimeWorkRequest
e RecurringWorkRequest
▢ OneTimeOffWorkRequest
e RecurringWorkRequest
Domanda 2
Quale delle seguenti classi utilizza WorkManager
per pianificare l'attività in background sull'API 23 e versioni successive?
▢ Solo JobScheduler
▢ BroadcastReceiver
e AlarmManager
▢ AlarmManager
e JobScheduler
▢ Scheduler
e BroadcastReceiver
Domanda 3
Quale API utilizzi per aggiungere vincoli a un WorkRequest
?
▢ setConstraints()
▢ addConstraints()
▢ setConstraint()
▢ addConstraintsToWorkRequest()
Inizia la lezione successiva:
Per i link ad altri codelab di questo corso, consulta la pagina di destinazione dei codelab di Android Kotlin Fundamentals.