web-dev-qa-db-fra.com

Comment WorkManager planifie-t-il les requêtes GET vers REST API?

J'ai jeté un coup d'œil à la liste de codes pour WorkManager et quelques exemples ici, mais tout ce que j'ai vu dans le code est lié au travail local sur l'appareil ou au téléchargement sur le serveur, sans télécharger les données et répondre aux données reçues . Dans les directives pour les développeurs, il est même dit: "Par exemple, une application peut avoir besoin de télécharger de nouvelles ressources à partir du réseau de temps en temps", donc j'ai pensé que ce serait parfait pour cette tâche. Ma question est de savoir si WorkManager peut gérer le scénario suivant et sinon, quel est l'outil approprié pour le gérer:

  1. Planifiez un travail qui s'exécute une fois par jour en arrière-plan
  2. Le travail consiste à effectuer une extraction de données à partir de l'API REST (et à le publier dans un objet LiveData si possible).
  3. Lorsque les données reviennent, vérifiez qu'elles sont plus récentes que les données locales.
  4. Informez l'utilisateur que de nouvelles données sont disponibles.

Ma classe ouvrière ressemble à ceci:

public class MyWorker extends Worker {

@NonNull
@Override
public WorkerResult doWork() {
    lookForNewData();
    return WorkerResult.SUCCESS;
}

public void lookForNewData() {
    MutableLiveData<MyObject> liveData = new MutableLiveData<>();

    liveData.observe(lifeCycleOwner, results -> {
        notifyOnNewData(results);
    })

    APILayer.getInstance().fetchData(searchParams, liveData)
}

Mon problème est bien sûr que l'objet LiveData ne peut pas observer car il n'y a aucune activité ou fragment qui peut être son LifecycleOwner. Mais même si j'avais utilisé un rappel de l'API pour répondre aux données qui arrivaient, mon travailleur aurait déjà signalé que cela avait réussi et il ne procéderait probablement pas au rappel, non? Je sais donc que cette approche est totalement fausse, mais je ne vois aucun code pour obtenir des données avec WorkManager

Veuillez aider avec une solution appropriée et un exemple de code ou des liens, soit avec WorkManager s'il peut gérer ce type de travail, soit autre chose s'il est plus approprié.

15
Arno Schoonbee
  1. Planifiez un travail qui s'exécute une fois par jour en arrière-plan

Vous pouvez planifier un PeriodicWorkRequest pour cela, qui devrait être mis en file d'attente avec enqueueUniquePeriodicWork. Cela garantit qu'un seul PeriodicWorkRequest d'un nom particulier peut être actif à la fois.

Constraints constraint = new Constraints.Builder()
     .setRequiredNetworkType(NetworkType.CONNECTED)
     .build();

PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(MyWorker.class, 1, TimeUnit.DAYS)
     .setConstraints(constraint)
     .build();

WorkManager workManager = WorkManager.getInstance();
workManager.enqueueUniquePeriodicWork("my_unique_worker", ExistingPeriodicWorkPolicy.KEEP, workRequest);
  1. Le travail consiste à effectuer une extraction de données à partir de l'API REST (et à le publier dans un objet LiveData si possible).

Cela peut être fait en envoyant votre demande de manière synchrone dans doWork() de votre collaborateur. Je n'utiliserais pas LiveData dans votre classe Worker. Nous y reviendrons plus tard. L'appel d'API ressemblerait par exemple à Retrofit:

@Override
public WorkerResult doWork() {
     Call<MyData> call = APILayer.getInstance().fetchData();
     Response<MyData> response = call.execute();
     if (response.code() == 200) {
          MyData data = response.body();
          // ...
     } else {
          return Result.RETRY;
     }
     // ...
     return Result.SUCCESS;
}
  1. Lorsque les données reviennent, vérifiez qu'elles sont plus récentes que les données locales.

Vous avez récupéré vos données API de manière synchrone. Récupérez également vos données locales de manière synchrone et faites tout ce que vous devez faire pour les comparer.

  1. Informez l'utilisateur que de nouvelles données sont disponibles.

Si vous planifiez une tâche avec WorkManager, son exécution est garantie, même si votre application est forcée à quitter ou si l'appareil est redémarré. Votre tâche peut donc se terminer pendant que votre application n'est pas en cours d'exécution. Si vous souhaitez informer l'utilisateur dans tous les cas, vous pouvez envoyer une notification. Si vous souhaitez informer l'utilisateur dans un certain écran, vous pouvez vous abonner sur l'état de vos tâches. Par exemple, comme ceci (tiré du guide officiel ):

WorkManager.getInstance().getStatusById(compressionWork.getId())
.observe(lifecycleOwner, workStatus -> {
    // Do something with the status
    if (workStatus != null && workStatus.getState().isFinished()) {
        // ...
    }
});

Il y a aussi getStatusesForUniqueWork(String uniqueWorkName) pour notre exemple.

Le guide officiel explique également comment renvoyer des données de votre tâche avec laquelle vous pouvez appeler setValue() sur votre MutableLiveData par exemple.

Je proposerais de mettre à jour vos données locales au sein de votre Worker, de vous abonner sur le statut de vos travailleurs et une fois qu'il aura réussi à mettre à jour votre interface utilisateur avec les données locales (si vous n'êtes de toute façon pas abonné à vos données locales, c'est-à-dire avec Room et LiveData).

Edit: En référence au point 4, l'état de lecture des demandes de travail périodiques fonctionne un peu différemment. Ils ne font que basculer entre ENQUEUED et RUNNING jusqu'à CANCELLED. Mais n'aura jamais l'état SUCCEEDED ou FAILED. Donc, écouter isFinished() n'est peut-être pas ce que vous attendez.

13
kphil

Telle est la pensée initiale. Quelqu'un, s'il vous plaît, corrigez-moi si je me trompe.

mon employé aurait déjà signalé qu'il a réussi et qu'il ne procéderait probablement pas au rappel, non?

nous pouvons utiliser le rappel de la réponse API, pour construire les données de sortie du travailleur et les définir à l'aide de worker.setOutputData() Ensuite, écoutez le LiveData<WorkStatus> de workManager. De ce statut de travail, nous pouvons obtenir outputData en utilisant, workStatus.getOutputdata(). Ces données peuvent nous donner la réponse API que nous voulons.

Nous pouvons transmettre cette réponse au prochain travailleur de la chaîne de travail pour effectuer des tâches telles que la mise à jour de la base de données locale.

0
Sudhasri