web-dev-qa-db-fra.com

OneTimeWorkRequest unique dans Workmanager

Nous utilisons OneTimeWorkRequest pour démarrer une tâche en arrière-plan dans notre projet. 

  1. Au démarrage de l'application, nous démarrons le OneTimeWorkRequest (disons A A) 
  2. Dépend de l'action de l'utilisateur, nous commençons la même demande de travail A.

Dans certains cas, si l'application est supprimée lorsque la demande de travail A est en cours, Android redémarre automatiquement la demande A au redémarrage de l'application. Une fois encore, nous commençons à nouveau la demande A. Donc, deux instances de la demande A s'exécutent en parallèle et mènent à une impasse. 

Pour éviter cela, j'ai vérifié ci-dessous dans App Start pour vérifier si le programme de travail est en cours d'exécution, mais renvoie toujours la valeur false. 

public static boolean isMyWorkerRunning(String tag) {
        List<WorkStatus> status = WorkManager.getInstance().getStatusesByTag(tag).getValue();
        return status != null;
    }

Y a-t-il une meilleure façon de gérer cela?

J'ai vérifié le beginUniqueWork (). Est-ce plus coûteux si je n'ai qu'une seule demande?

Éditer 2: Cette question concerne une tâche unique et ponctuelle. Pour démarrer une tâche périodique unique, nous avions une API distincte enqueueUniquePeriodicWork (). Mais nous n'avions pas d'API pour démarrer un travail ponctuel unique. J'étais confus d'utiliser entre l'objet de continuation ou de vérifier manuellement et de commencer l'approche. 

Lors de la construction récente, Android a ajouté une nouvelle API pour cette enqueueUniqueWork (). C'est la raison exacte qu'ils ont mentionnée dans leurs notes de publication. 

Ajoutez l'API WorkManager.enqueueUniqueWork () pour mettre en file d'attente unique OneTimeWorkRequests sans avoir à créer de WorkContinuation. https://developer.Android.com/jetpack/docs/release-notes

5
Aram

Edit 2:

Notes de publication du 8 novembre:

https://developer.Android.com/jetpack/docs/release-notes

Ajoutez l'API WorkManager.enqueueUniqueWork () pour mettre en file d'attente unique OneTimeWorkRequests sans avoir à créer un WorkContinuation.

Cela dit, alpha11 dispose de cette nouvelle API pour mettre en file d'attente unique un travail unique. 

J'ai essayé de changer le code comme suit:

OneTimeWorkRequest impWork = new OneTimeWorkRequest.Builder(WorkerNotesAttachment.class)
            .addTag(RWORK_TAG_NOTES)
            .build();
WorkManager.getInstance().enqueueUniqueWork(RWORK_TAG_NOTES, ExistingWorkPolicy.REPLACE, impWork);

J'ai essayé d'utiliser l'API beginUniqueWork. Mais ça ne fonctionne pas parfois. J'ai donc fini par écrire la fonction suivante. 

public static boolean isMyWorkerRunning(String tag) {
    List<WorkStatus> status = null;
    try {
        status = WorkManager.getInstance().getStatusesByTag(tag).get();
        boolean running = false;
        for (WorkStatus workStatus : status) {
            if (workStatus.getState() == State.RUNNING
                    || workStatus.getState() == State.ENQUEUED) {
                return true;
            }
        }
        return false;

    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
    return false;
}

Nous devons obtenir tous les objets WorkStatus et vérifier si au moins l'un d'entre eux est en cours d'exécution ou en attente. Comme le système conserve tous les travaux terminés dans la base de données pendant quelques jours (reportez-vous à pruneWork ()), nous devons vérifier toutes les instances de travail.

Appelez cette fonction avant de démarrer OneTimeWorkRequest.

public static void startCacheWorker() {

    String tag = RWORK_TAG_CACHE;

    if (isMyWorkerRunning(tag)) {
        log("worker", "RWORK: tag already scheduled, skipping " + tag);
        return;
    }
    // Import contact for given network
    OneTimeWorkRequest impWork = new OneTimeWorkRequest.Builder(WorkerCache.class)
            .addTag(tag)
            .build();
    WorkManager.getInstance().enqueue(impWork);
}
2
Aram

Vous pouvez utiliser beginUniqueWork() avec un nom unique.
Si vous utilisez ExistingWorkPolicy :
APPEND: les 2 requêtes seront exécutées en série.
KEEP: n'exécutera pas la deuxième demande si la première est en cours d'exécution.
REMPLACER: les 2 requêtes s'exécuteront en parallèle.

1
NickF

Utiliser getStatusesByTag renvoie LiveData de List<WorkStatus> Il a été créé en tant que LiveData, car WorkStatus est conservé dans la base de données de pièce et WorkManger doit l’interroger en premier sur le fil d’arrière-plan, puis transmettre le résultat. valeur réelle quand elle est disponible. appeler getValue() renverra la dernière valeur de LiveData qui n’est pas disponible au moment où vous l’appelez.

Ce que tu peux faire 

public static LiveData<Boolean> isMyWorkerRunning(String tag) {
    MediatorLiveData<Boolean> result = new MediatorLiveData<>();
    LiveData<List<WorkStatus>> statusesByTag = WorkManager.getInstance().getStatusesByTag(tag);
    result.addSource(statusesByTag, (workStatuses) -> {
        boolean isWorking;
        if (workStatuses == null || workStatuses.isEmpty())
            isWorking = false;
        else {
            State workState = workStatuses.get(0).getState();
            isWorking = !workState.isFinished();
        }
        result.setValue(isWorking);
        //remove source so you don't get further updates of the status
        result.removeSource(statusesByTag);
    });
    return result;
}

Maintenant, vous ne commencez pas la tâche tant que vous n’observez pas la valeur renvoyée d’isMyWorkerRunning si elle est vraie, c’est prudent de la démarrer, sinon cela signifie qu’une autre tâche portant la même balise est en cours d’exécution. 

1
Omar El Hefny