Threading in CoroutineWorker

Per gli utenti di Kotlin, WorkManager fornisce un'assistenza di primo livello per le coroutine. Per iniziare, includi work-runtime-ktx nel file Gradle. Anziché estendere Worker, devi estendere CoroutineWorker, che ha una versione in sospensione di doWork(). Ad esempio, se vuoi creare un semplice CoroutineWorker per eseguire alcune operazioni di rete, devi procedere nel seguente modo:

class CoroutineDownloadWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        val data = downloadSynchronously("https://www.google.com")
        saveData(data)
        return Result.success()
    }
}

Tieni presente che CoroutineWorker.doWork() è una funzione di sospensione. A differenza di Worker, questo codice non viene eseguito sul Executor specificato nel tuo Configuration. Al suo posto, viene utilizzato il valore predefinito Dispatchers.Default. Puoi personalizzarlo fornendo il tuo CoroutineContext. Nell'esempio precedente, probabilmente vorrai eseguire questa operazione su Dispatchers.IO, come segue:

class CoroutineDownloadWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        withContext(Dispatchers.IO) {
            val data = downloadSynchronously("https://www.google.com")
            saveData(data)
            return Result.success()
        }
    }
}

CoroutineWorker gestisce automaticamente gli arresti annullando la coroutine e propagando gli indicatori di annullamento. Non devi fare nulla di speciale per gestire gli interruzioni del lavoro.

Esecuzione di un CoroutineWorker in un processo diverso

Puoi anche associare un worker a un processo specifico utilizzando RemoteCoroutineWorker, un'implementazione di ListenableWorker.

RemoteCoroutineWorker si lega a un processo specifico con due argomenti aggiuntivi che fornisci come parte dei dati di input durante la creazione della richiesta di lavoro: ARGUMENT_CLASS_NAME e ARGUMENT_PACKAGE_NAME.

L'esempio seguente mostra la creazione di una richiesta di lavoro associata a un procedura specifica:

Kotlin

val PACKAGE_NAME = "com.example.background.multiprocess"

val serviceName = RemoteWorkerService::class.java.name
val componentName = ComponentName(PACKAGE_NAME, serviceName)

val data: Data = Data.Builder()
   .putString(ARGUMENT_PACKAGE_NAME, componentName.packageName)
   .putString(ARGUMENT_CLASS_NAME, componentName.className)
   .build()

return OneTimeWorkRequest.Builder(ExampleRemoteCoroutineWorker::class.java)
   .setInputData(data)
   .build()

Java

String PACKAGE_NAME = "com.example.background.multiprocess";

String serviceName = RemoteWorkerService.class.getName();
ComponentName componentName = new ComponentName(PACKAGE_NAME, serviceName);

Data data = new Data.Builder()
        .putString(ARGUMENT_PACKAGE_NAME, componentName.getPackageName())
        .putString(ARGUMENT_CLASS_NAME, componentName.getClassName())
        .build();

return new OneTimeWorkRequest.Builder(ExampleRemoteCoroutineWorker.class)
        .setInputData(data)
        .build();

Per ogni RemoteWorkerService, devi anche aggiungere una definizione di servizio nel file AndroidManifest.xml:

<manifest ... >
    <service
            android:name="androidx.work.multiprocess.RemoteWorkerService"
            android:exported="false"
            android:process=":worker1" />

        <service
            android:name=".RemoteWorkerService2"
            android:exported="false"
            android:process=":worker2" />
    ...
</manifest>