Unique OneTimeWorkRequest in Workmanager











up vote
4
down vote

favorite
3












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




  1. At application start, we are starting the OneTimeWorkRequest (say req A)

  2. Depends on user's action we start the same work request A.


At some cases, if the app gets killed when the work request A is in progress, Android automatically restarts the request A when the app restarts. Once again we are also starting the request A again. So two instances of the request A runs in parallel and leads to a deadlock.



To avoid this, I did below code in app start to check if the worker is running but this always returns false.



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


Is there a better way to handle this?



I checked the beginUniqueWork(). Is it costlier if I have only one request?










share|improve this question
























  • Why are you re-running the task, aren't you suppose to fire and forget?
    – Paul Okeke
    Aug 8 at 22:01










  • No, OneTimeWorkRequest is just one-time-fire. We do not run this worker periodically. I run this worker during app restart because, app does not know how much time app was not running. This worker used to sync with phonebook content.
    – Aram
    Aug 9 at 3:52










  • Possible duplicate of Check if WorkManager is scheduled already
    – Khemraj
    35 mins ago















up vote
4
down vote

favorite
3












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




  1. At application start, we are starting the OneTimeWorkRequest (say req A)

  2. Depends on user's action we start the same work request A.


At some cases, if the app gets killed when the work request A is in progress, Android automatically restarts the request A when the app restarts. Once again we are also starting the request A again. So two instances of the request A runs in parallel and leads to a deadlock.



To avoid this, I did below code in app start to check if the worker is running but this always returns false.



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


Is there a better way to handle this?



I checked the beginUniqueWork(). Is it costlier if I have only one request?










share|improve this question
























  • Why are you re-running the task, aren't you suppose to fire and forget?
    – Paul Okeke
    Aug 8 at 22:01










  • No, OneTimeWorkRequest is just one-time-fire. We do not run this worker periodically. I run this worker during app restart because, app does not know how much time app was not running. This worker used to sync with phonebook content.
    – Aram
    Aug 9 at 3:52










  • Possible duplicate of Check if WorkManager is scheduled already
    – Khemraj
    35 mins ago













up vote
4
down vote

favorite
3









up vote
4
down vote

favorite
3






3





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




  1. At application start, we are starting the OneTimeWorkRequest (say req A)

  2. Depends on user's action we start the same work request A.


At some cases, if the app gets killed when the work request A is in progress, Android automatically restarts the request A when the app restarts. Once again we are also starting the request A again. So two instances of the request A runs in parallel and leads to a deadlock.



To avoid this, I did below code in app start to check if the worker is running but this always returns false.



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


Is there a better way to handle this?



I checked the beginUniqueWork(). Is it costlier if I have only one request?










share|improve this question















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




  1. At application start, we are starting the OneTimeWorkRequest (say req A)

  2. Depends on user's action we start the same work request A.


At some cases, if the app gets killed when the work request A is in progress, Android automatically restarts the request A when the app restarts. Once again we are also starting the request A again. So two instances of the request A runs in parallel and leads to a deadlock.



To avoid this, I did below code in app start to check if the worker is running but this always returns false.



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


Is there a better way to handle this?



I checked the beginUniqueWork(). Is it costlier if I have only one request?







android android-architecture-components android-jetpack android-workmanager android-architecture-workmanager






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Aug 13 at 13:00









M.G

7321525




7321525










asked Aug 7 at 10:49









Aram

207116




207116












  • Why are you re-running the task, aren't you suppose to fire and forget?
    – Paul Okeke
    Aug 8 at 22:01










  • No, OneTimeWorkRequest is just one-time-fire. We do not run this worker periodically. I run this worker during app restart because, app does not know how much time app was not running. This worker used to sync with phonebook content.
    – Aram
    Aug 9 at 3:52










  • Possible duplicate of Check if WorkManager is scheduled already
    – Khemraj
    35 mins ago


















  • Why are you re-running the task, aren't you suppose to fire and forget?
    – Paul Okeke
    Aug 8 at 22:01










  • No, OneTimeWorkRequest is just one-time-fire. We do not run this worker periodically. I run this worker during app restart because, app does not know how much time app was not running. This worker used to sync with phonebook content.
    – Aram
    Aug 9 at 3:52










  • Possible duplicate of Check if WorkManager is scheduled already
    – Khemraj
    35 mins ago
















Why are you re-running the task, aren't you suppose to fire and forget?
– Paul Okeke
Aug 8 at 22:01




Why are you re-running the task, aren't you suppose to fire and forget?
– Paul Okeke
Aug 8 at 22:01












No, OneTimeWorkRequest is just one-time-fire. We do not run this worker periodically. I run this worker during app restart because, app does not know how much time app was not running. This worker used to sync with phonebook content.
– Aram
Aug 9 at 3:52




No, OneTimeWorkRequest is just one-time-fire. We do not run this worker periodically. I run this worker during app restart because, app does not know how much time app was not running. This worker used to sync with phonebook content.
– Aram
Aug 9 at 3:52












Possible duplicate of Check if WorkManager is scheduled already
– Khemraj
35 mins ago




Possible duplicate of Check if WorkManager is scheduled already
– Khemraj
35 mins ago












3 Answers
3






active

oldest

votes

















up vote
0
down vote













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.






share|improve this answer





















  • Ok, That is my exact question. If i invoke beginUniqueWork(), it returns continuation object. If I have only one work request, will that be costlier? I mean I dont have a chain of work requests. We have only one work request.
    – Aram
    Sep 3 at 6:27


















up vote
0
down vote













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






share|improve this answer






























    up vote
    0
    down vote



    accepted










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





    share|improve this answer























      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














       

      draft saved


      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51724971%2funique-onetimeworkrequest-in-workmanager%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      0
      down vote













      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.






      share|improve this answer





















      • Ok, That is my exact question. If i invoke beginUniqueWork(), it returns continuation object. If I have only one work request, will that be costlier? I mean I dont have a chain of work requests. We have only one work request.
        – Aram
        Sep 3 at 6:27















      up vote
      0
      down vote













      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.






      share|improve this answer





















      • Ok, That is my exact question. If i invoke beginUniqueWork(), it returns continuation object. If I have only one work request, will that be costlier? I mean I dont have a chain of work requests. We have only one work request.
        – Aram
        Sep 3 at 6:27













      up vote
      0
      down vote










      up vote
      0
      down vote









      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.






      share|improve this answer












      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.







      share|improve this answer












      share|improve this answer



      share|improve this answer










      answered Aug 30 at 11:37









      NickF

      3,01683460




      3,01683460












      • Ok, That is my exact question. If i invoke beginUniqueWork(), it returns continuation object. If I have only one work request, will that be costlier? I mean I dont have a chain of work requests. We have only one work request.
        – Aram
        Sep 3 at 6:27


















      • Ok, That is my exact question. If i invoke beginUniqueWork(), it returns continuation object. If I have only one work request, will that be costlier? I mean I dont have a chain of work requests. We have only one work request.
        – Aram
        Sep 3 at 6:27
















      Ok, That is my exact question. If i invoke beginUniqueWork(), it returns continuation object. If I have only one work request, will that be costlier? I mean I dont have a chain of work requests. We have only one work request.
      – Aram
      Sep 3 at 6:27




      Ok, That is my exact question. If i invoke beginUniqueWork(), it returns continuation object. If I have only one work request, will that be costlier? I mean I dont have a chain of work requests. We have only one work request.
      – Aram
      Sep 3 at 6:27












      up vote
      0
      down vote













      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






      share|improve this answer



























        up vote
        0
        down vote













        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






        share|improve this answer

























          up vote
          0
          down vote










          up vote
          0
          down vote









          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






          share|improve this answer














          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







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Oct 11 at 13:32

























          answered Oct 10 at 14:26









          Omar El Hefny

          116




          116






















              up vote
              0
              down vote



              accepted










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





              share|improve this answer



























                up vote
                0
                down vote



                accepted










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





                share|improve this answer

























                  up vote
                  0
                  down vote



                  accepted







                  up vote
                  0
                  down vote



                  accepted






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





                  share|improve this answer














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






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 19 at 12:11

























                  answered Nov 9 at 8:23









                  Aram

                  207116




                  207116






























                       

                      draft saved


                      draft discarded



















































                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51724971%2funique-onetimeworkrequest-in-workmanager%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      android studio warns about leanback feature tag usage required on manifest while using Unity exported app?

                      SQL update select statement

                      'app-layout' is not a known element: how to share Component with different Modules