Threading in un worker

Quando utilizzi una Worker, WorkManager chiama automaticamente Worker.doWork() in un thread in background. Il thread in background proviene da Executor specificato in Configuration di WorkManager. Per impostazione predefinita, WorkManager configura un Executor per te, ma puoi anche personalizzarlo la tua. Ad esempio, puoi condividere un esecutore in background esistente crea un Executor a thread unico per assicurarti che tutto il lavoro in background vengono eseguiti in sequenza o anche specificare un Executor personalizzato. Per personalizzare Executor, assicurati di inizializzare WorkManager manualmente.

Quando configuri WorkManager manualmente, puoi specificare Executor come che segue:

Kotlin

WorkManager.initialize(
    context,
    Configuration.Builder()
         // Uses a fixed thread pool of size 8 threads.
        .setExecutor(Executors.newFixedThreadPool(8))
        .build())

Java

WorkManager.initialize(
    context,
    new Configuration.Builder()
        .setExecutor(Executors.newFixedThreadPool(8))
        .build());

Ecco un esempio di Worker semplice che scarica i contenuti di una pagina web 100 volte:

Kotlin

class DownloadWorker(context: Context, params: WorkerParameters) : Worker(context, params) {

    override fun doWork(): ListenableWorker.Result {
        repeat(100) {
            try {
                downloadSynchronously("https://www.google.com")
            } catch (e: IOException) {
                return ListenableWorker.Result.failure()
            }
        }

        return ListenableWorker.Result.success()
    }
}

Java

public class DownloadWorker extends Worker {

    public DownloadWorker(Context context, WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public Result doWork() {
        for (int i = 0; i < 100; i++) {
            try {
                downloadSynchronously("https://www.google.com");
            } catch (IOException e) {
                return Result.failure();
            }
        }

        return Result.success();
    }

}

Tieni presente che Worker.doWork() è un sincrona: devi svolgere interamente il lavoro in background in modo da bloccarlo e terminarlo nel momento in cui il metodo viene chiuso. Se chiami l'API asincrona in doWork() e restituisce un valore Result, il callback potrebbe non funzionino correttamente. Se ti trovi in questa situazione, potresti utilizzare un ListenableWorker (vedi Threading in ListenableWorker).

Quando un Worker attualmente in esecuzione viene interrotto per qualsiasi motivo, riceve una chiamata al numero Worker.onStopped(). Esegui l'override di questo metodo o chiama Worker.isStopped() per controllare il codice e liberare risorse quando necessario. Quando Worker nell'esempio precedente è arrestata, potrebbe trovarsi nel mezzo del suo loop di scaricare elementi e continuerà a farlo anche se l'operazione è stata interrotta. A per ottimizzare questo comportamento, puoi procedere in questo modo:

Kotlin

class DownloadWorker(context: Context, params: WorkerParameters) : Worker(context, params) {

    override fun doWork(): ListenableWorker.Result {
        repeat(100) {
            if (isStopped) {
                break
            }

            try {
                downloadSynchronously("https://www.google.com")
            } catch (e: IOException) {
                return ListenableWorker.Result.failure()
            }

        }

        return ListenableWorker.Result.success()
    }
}

Java

public class DownloadWorker extends Worker {

    public DownloadWorker(Context context, WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public Result doWork() {
        for (int i = 0; i < 100; ++i) {
            if (isStopped()) {
                break;
            }

            try {
                downloadSynchronously("https://www.google.com");
            } catch (IOException e) {
                return Result.failure();
            }
        }

        return Result.success();
    }
}

Una volta interrotto un Worker, non importa da cosa torni Worker.doWork(); Result verrà ignorato.