Running two separate workers - android

I'm trying to run two separate Workers, When I start one worker I'm unable to start the other worker. I feel like I might be missing something to close the worker allowing me to start another worker.
Fragment
Constraints myConstrainst = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.build();
OneTimeWorkRequest workerOne = new OneTimeWorkRequest.Builder(WorkerOne.class)
.setConstraints(myConstraints)
.addTag("WorkerOne")
.build();
OneTImeWorkRequest workerTwo = new OneTimeWorkRequest.Builder(WorkerTwo.class)
.setConstraints(myConstrains)
.addTag("WorkerTwo")
.build();
btnOne.setOnClickListener(view -> {
WorkMananger.getInstance(getActivity()).enqueue(workerOne);
});
btnTwo.setOnClickListener(view -> {
WorkManager.getInstance(getActivity()).enqueue(workerTwo);
});
WorkerOne
public class WorkerOne extends Worker {
public WorkerOne(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
#Override
public Result doWork() {
for(int i = 0; i < 5; i++) {
Log.d("WorkerOne", "doWork " + i);
SystemClock.sleep(1000);
}
return Result.success();
}
}
WorkerTwo
public class WorkerTwo extends Worker {
public WorkerTwo(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
#Override
public Result doWork() {
for(int i = 0; i < 5; i++) {
Log.d("WorkerTwo", "doWork " + i);
SystemClock.sleep(1000);
}
return Result.success();
}
}

Your code is working fine with my test, both workers do their job,
As got from comments, filtering logcat not that right so you just get logs from one Worker while filtering out the other Worker's log.
This can be confirmed by debugging code with break points in both doWork().
EDIT
This is a request from comments not relevant to the question
I press btnOne to run workerOne and wait for the work to finish. If I
press btnOne a second time nothing happens
OneTimeWorkRequest is supposed to work only once, if you want to repeat the work you can instantiate the OneTimeWorkRequest object within the callback of your button, so it will be a new object with a new work request
btnOne.setOnClickListener(view -> {
OneTimeWorkRequest workerOne = new OneTimeWorkRequest.Builder(WorkerOne.class)
.setConstraints(myConstraints)
.addTag("WorkerOne")
.build();
WorkManager.getInstance(getActivity()).enqueue(workerOne);
});

Might be a case that your worker Constraint not match with current condition of your device. Please check your Constraint.

Related

How to execute a method continuosly even if the app is killed or is in background

I want to continuosly execute a method even if the app is not in foreground. For this I have used WorkManager. But problem with this is minimum time delay is 15min, and we cannot reduce this value. Below is the code.
final PeriodicWorkRequest periodicWorkRequest
= new PeriodicWorkRequest.Builder(MyWorker.class, 10, TimeUnit.SECONDS)
.build();
WorkManager.getInstance().enqueue(periodicWorkRequest);
public class MyWorker extends Worker {
public MyWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
#NonNull
#Override
public Result doWork() {
//Do work
return Result.success();
}}
How can I achieve this ? Which is the best approach for this ?
For intervals as short as this (10 secs) WorkManager or AlarmManager are not suitable. Use Java executors:
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
// Do work
}
}, 0, 10, TimeUnit.SECONDS);
Don't forget to shutdown the executor when you're done with it:
executor.shutdown()

Android Workmanager

I'm having trouble figuring out how to use Android's Workmanager. Essentially, I want to make a OneTime request with a time delay, determine success, then do some stuff. The Worker class does NOTHING.
What I'm expecting is a SUCCESS code to be returned after the time delay. That is, the sole purpose of my Workmanager code is to provide a delay.
I know there are many other ways to effect a delay but my understanding is that Android "protects" Workmanager Workers better than, say, AlarmManager.
Unfortunately, I can't make it happen.
Here's what I've done
Extended my activity to include LifecycleOwner
Added the required getLifeCycle method, as below
#NonNull
#Override
public Lifecycle getLifecycle() {
Log.d (TAG, "getLifecycle(): " + getLifecycle());
return getLifecycle();
}
Here's the Worker class
public class makeAlarm extends Worker {
public makeAlarm(
#NonNull Context context,
#NonNull WorkerParameters params) {
super(context, params);
}
#Override
public Result doWork() {
// Do the work here--in this case, do nothing
// Indicate whether the task finished successfully with the Result
return Result.success();
}
}
And here's my action code
// Create a OneTimeWorkRequest that delays "success" by the required time
OneTimeWorkRequest makeAlarmWorkRequest = new OneTimeWorkRequest.Builder(makeAlarm.class)
.setInitialDelay(120, TimeUnit.SECONDS)
.build();
WorkManager.getInstance(this).enqueue(makeAlarmWorkRequest);
// The following stmt. shows what appears to be a valid id
Log.d (TAG, "makeAlarmWorkRequest.getId(): " + makeAlarmWorkRequest.getId());
WorkManager.getInstance(this).getWorkInfoByIdLiveData(makeAlarmWorkRequest.getId())
.observe(myLifecycleOwner, new Observer<WorkInfo>() {
#Override
public void onChanged(#Nullable WorkInfo workInfo) {
if (workInfo != null && workInfo.getState() == WorkInfo.State.SUCCEEDED) {
// Some amazing work here...
}
}
});
I've tried a number of variations but haven't had success.
The above code results in a stack overflow crash.
Help!

Android WorkManager not starting the worker

I want to download certain files from the server at the start of the app .So I tried using Work Manager which gets enqueued from my custom Application class.But the Worker class is not getting triggered and the state is only ENQUEUED and not going to RUNNING.Below is my code:
Application class:
#Override
public void onCreate() {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
//.setRequiresStorageNotLow(true)
//.setRequiresBatteryNotLow(true)
.build();
OneTimeWorkRequest request = new OneTimeWorkRequest
.Builder(MyWorker.class)
//.setConstraints(constraints)
//.setInitialDelay(1,TimeUnit.SECONDS)
.addTag("download")
.build();
WorkManager.getInstance(getApplicationContext()).getWorkInfoByIdLiveData(request.getId()).observeForever(new Observer<WorkInfo>() {
#Override
public void onChanged(WorkInfo workInfo) {
if (workInfo == null) {
Log.d("download", "workInfo == null");
} else {
Log.d("download", "workInfo != null: " + workInfo.getState().toString());//This is giving ENQUEUED once..thats it
}
}
});
WorkManager.getInstance(getApplicationContext()).enqueue(request);
}
MyWorker class
public class MyWorker extends Worker {
public MyWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
#NonNull
#Override
public Result doWork() {
//Some file to download
}
}
build.gradle:
implementation "androidx.work:work-runtime:2.3.2"
Things i have tried:
I tried adding an interval and also remove constraints, but then also, MyWorker is not triggered.
I have seen many SOF posts as given below but it didn't help me:
Worker manager: not start work in enqueue
Why workers in work manager still in ENQUEUED state?
Android WorkManager doesn't trigger one of the two scheduled workers

Is it better to use multiple workers that perform the same task for inputs or one worker that performs the task multiple times for inputs?

Is it better to use multiple workers that perform the same task for inputs or one worker that performs the task multiple times for inputs?
1 worker :
\\\ SomeWorker.class
#NonNull
#Override
public Worker.Result doWork() {
Context applicationContext = getApplicationContext();
boolean success = Boolean.TRUE;
List<String> resourceUris = new ArrayList<String>(has a list of strings);
for (String resourceUri : resourceUris) {
success = doSomething(resourceUri);
}
return success ? Result.success() : Result.retry();
}
\\\ Viewmodel.class
OneTimeWorkRequest save = new OneTimeWorkRequest.Builder(SomeWorker.class)
.addTag(TAG_OUTPUT)
.build();
workManager.beginUniqueWork(save).enqueue();
Vs
Multiple workers which do one task independently :
\\\ Someworker.class
#NonNull
#Override
public Worker.Result doWork() {
Context applicationContext = getApplicationContext();
String resourceUri = getInputData().getString("RESOURCE_URI");
return doSomething(resourceUri) ? Result.success() : Result.retry();
}
\\\ Viewmodel.class
List<String> resourceUris = new ArrayList<String>(has a list of strings);
List<OneTimeWorkRequest.Builder> someBuilder;
for (int i = 0; i < resourceUris.size(); i++) {
someBuilder.add( new OneTimeWorkRequest.Builder(Someworker.class));
}
workManager.beginUniqueWork(someBuilder).enqueue();
It seems like the first approach will consume less memory but will take longer vs the second which will consume more memory due to more work managers but will take shorter time.
It depends.
I would say use one Worker unless you know you might run over the 10 minute execution window, or if you know there are parts of the Worker that are useful independently (i.e. reusable from other parts of the app).

WorkManager onStopped() method called twice

I have implemented WorkManager in my project. After finishing my task in doWork(), I've called stop(true); And I've sending a Broadcast to another activity in onStopped(). Everything is working fine but the problem is onStopped() is being called twice (I've tested by applying breakpoints). As a result the BroadcastReceiver is also called twice.
I know that the WorkManager is in alpha stage. But I'm not actually sure if this is a bug or I am doing something wrong. Please help. Codes are as follows:
public Result doWork() {
startGettingData();
stop(true);
return Result.SUCCESS;
}
#Override
public void onStopped(boolean cancelled) {
super.onStopped(cancelled);
Intent intent=new Intent(SERVER_SYNC_BROADCAST);
intent.putExtra(SYNC_RESULT_MESSAGE,responseCodes);
LocalBroadcastManager.getInstance(MyApplication.getContext()
.getApplicationContext())
.sendBroadcast(intent);
}
Calling from activity's onCreate() just once:
WorkUtil.startSyncing(SyncWorker.class);
WorkUtil.java
public class WorkUtil {
private static WorkManager mWorkManager;
public static WorkUtil workUtil;
private WorkUtil() {
mWorkManager = WorkManager.getInstance();
}
public static WorkUtil getInstance() {
if(workUtil == null) {
workUtil = new WorkUtil();
}
return workUtil;
}
public static void startSyncing(Class workerClass) {
Constraints constraints = new Constraints.Builder().build();
OneTimeWorkRequest someWork = new OneTimeWorkRequest.Builder(workerClass)
.setConstraints(constraints)
.build();
OneTimeWorkRequest oneTimeWorkRequest = someWork;
mWorkManager.enqueue(oneTimeWorkRequest);
}
public static void cancelAllWork() {
mWorkManager.cancelAllWork();
}
}
If I understand you correctly, you want to send a broadcast when your work is done.
You shouldn't do it inside onStopped, move it to the doWork like this:
public Result doWork() {
startGettingData(); // this method should be synchronous
Intent intent=new Intent(SERVER_SYNC_BROADCAST);
intent.putExtra(SYNC_RESULT_MESSAGE,responseCodes);
LocalBroadcastManager.getInstance(MyApplication.getContext()
.getApplicationContext())
.sendBroadcast(intent);
return Result.SUCCESS;
}
The onStopped method is not meant to be called when the work is done, but when it's stopped or canceled.
Source

Categories

Resources