Unique OneTimeWorkRequest in Workmanager

前端 未结 4 1544
[愿得一人]
[愿得一人] 2020-12-31 09:07

We are using OneTimeWorkRequest to start background task in our project.

  1. At application start, we are starting the OneTimeWorkRequest (say req A)
  2. De
相关标签:
4条回答
  • 2020-12-31 09:11

    Edit 2:

    Nov 8th release notes:

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

    Add WorkManager.enqueueUniqueWork() API to enqueue unique OneTimeWorkRequests without having to create a WorkContinuation.

    This says, alpha11 has this new API to uniquely enqueue a onetimework.

    I tried changing the code as follows:

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

    I tried using the beginUniqueWork API. But it fails to run sometimes. So I ended up writing the following function.

    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;
    }
    

    We need to get all the WorkStatus objects and check if atleast one of them is in running or Enqueued state. As the system keeps all the completed works in the DB for few days (Refer pruneWork()), we need to check all the work instances.

    Invoke this function before starting the 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);
    }
    
    0 讨论(0)
  • 2020-12-31 09:19

    Using getStatusesByTag returns LiveData of List<WorkStatus> it was made as LiveData because WorkStatus is kept in Room DB and WorkManger has to query it first on background thread then deliver the result. so you must observe to get the real value when it's available . calling getValue() will return last value of the LiveData which isn't available on the time you call it.

    What you can do

    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;
    }
    

    Now you don't start the task until you observe on the returning value of isMyWorkerRunning if it's true then it's safe to start it if not this mean that another task with the same tag is running

    0 讨论(0)
  • 2020-12-31 09:20

    You can use beginUniqueWork() with a unique name.
    If you use ExistingWorkPolicy:
    APPEND: the 2 requests will run serial.
    KEEP: will not run the second request if the first is running.
    REPLACE: the 2 requests will run parallel.

    0 讨论(0)
  • 2020-12-31 09:27

    Since all of the answers are mostly outdated, you can listen for changes on a tagged worker like this:

     LiveData<List<WorkInfo>> workInfosByTag = WorkManager.getInstance().getWorkInfosByTagLiveData(tag);
            workInfosByTag.observeForever(workInfos -> {
    
                for (WorkInfo workInfo : workInfos) {
                    workInfo.toString();
    
                }
            });
    
    0 讨论(0)
提交回复
热议问题