My goal is to run a simple task once an hour. At application start, I register an unique periodic work with ExistingPeriodicWorkPolicy.KEEP flag.
Here's my implementation:
public class MyWorker extends Worker {
public MyWorker(Context context, WorkerParameters workerParams) {
super(context, workerParams);
// I don't do anyting with workerParams
}
public static void enqueueWork() {
Constraints constraints = new Constraints.Builder()
.setRequiresBatteryNotLow(true)
.build();
PeriodicWorkRequest request = new PeriodicWorkRequest
.Builder(MyWorker.class, 1, TimeUnit.HOURS)
.setConstraints(constraints)
.addTag("MyWorkerWork")
.build();
WorkManager.getInstance().enqueueUniquePeriodicWork("MyWorkerWork",
ExistingPeriodicWorkPolicy.KEEP, request);
}
#NonNull
#Override
public Result doWork() {
Log.i(TAG, "doWork");
return Result.success();
}
}
The only place I call enqueueWork() is at Application#onCreate.
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
MyWorker.enqueueWork();
}
}
Above setup runs somewhat okay. One of the problems is that sometimes doWork is called twice in a row, with ~30 sec of time in between. This is not 100% reproducible but I see this often when I leave the phone overnight and come back next day and turn on the phone display for the first time.
Typical log would look like this:
01-13 13:29:04.601 19018 19449 I/MyApp: doWork
01-13 13:29:04.700 19018 19124 I/WM-WorkerWrapper: Worker result SUCCESS for Work [ id=37064d6c-297b-4c0d-9fd7-xxxxxxxxxxxx, tags={ com.xxx.MyWorker, MyWorkerWork } ]
01-13 13:29:42.203 19018 19482 I/MyApp: doWork
01-13 13:29:42.292 19018 19145 I/WM-WorkerWrapper: Worker result SUCCESS for Work [ id=37064d6c-297b-4c0d-9fd7-xxxxxxxxxxxx, tags={ com.xxx.MyWorker, MyWorkerWork } ]
The interesting thing is that this happens WITHOUT process getting killed. If you experienced this before, please help.
Related
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()
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!
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
I am using WorkManager to schedule some tasks but the problem is that work manager is executing those tasks { doWork() } more than once in a single call.
I am using:
'android.arch.work:work-runtime:1.0.0-alpha08'
I have tried using -alpha07,06,05,04. But I have same issue. Sometimes it even executes 5-6 times at once
Here is the code:
public class MyWorker extends Worker {
#NonNull
#Override
public Result doWork() {
Log.i("CountWorker","0");
sendNotification("Notice", "A notice was sent");
return Result.SUCCESS;
}
This is the Activity
public class MyWorkerActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final PeriodicWorkRequest pwr = new PeriodicWorkRequest
.Builder(MyWorker.class, 16, TimeUnit.MINUTES)
.setConstraints(Constraints.NONE)
.build();
WorkManager.getInstance().enqueue(pwr);
}
}
This is the result from Logcat:
09-24 16:44:35.954 22779-22816/com.simran.powermanagement I/CountWorker: 0
09-24 16:44:35.970 22779-22817/com.simran.powermanagement I/CountWorker: 0
09-24 16:44:35.977 22779-22818/com.simran.powermanagement I/CountWorker: 0
When you enqueue a PeriodicWorkRequest, that does not cancel any existing PeriodicWorkRequest that you have previously enqueued. Therefore as you have written your app, every time your activity starts, you add yet periodic work request, slowly going from 1 to 2 to 3 onward.
You instead want to use enqueueUniquePeriodicWork():
This method allows you to enqueue a uniquely-named PeriodicWorkRequest, where only one PeriodicWorkRequest of a particular name can be active at a time. For example, you may only want one sync operation to be active. If there is one pending, you can choose to let it run or replace it with your new work. The uniqueWorkName uniquely identifies this PeriodicWorkRequest.
With code such as:
final PeriodicWorkRequest pwr = new PeriodicWorkRequest
.Builder(MyWorker.class, 16, TimeUnit.MINUTES)
.setConstraints(Constraints.NONE)
.build();
WorkManager.getInstance().enqueueUniquePeriodicWork(
"my_worker",
ExistingPeriodicWorkPolicy.REPLACE,
pwr);
For OneTimeWorkRequest using version 1.0.0-beta01
WorkManager.getInstance()
.beginUniqueWork("Unique", ExistingWorkPolicy.KEEP, oneTimeWorkRequest)
.enqueue();
Cancel the existing sequence and REPLACE it with the new one.
KEEP the existing sequence and ignore your new request.
APPEND your new sequence to the existing one, running the new sequence's first task after the existing sequence's last task finishes
Official Documentation. https://developer.android.com/topic/libraries/architecture/workmanager/advanced
I am trying to schedule work when app start after 1 mint I need do some work it does not matter app still in the foreground or not but I need to do this take, but I don't know why my doWork method not run.but onStart mathod called multiple time
private void sacduleThePaddingNotifaction() {
OneTimeWorkRequest postNotationWithDelay =
new OneTimeWorkRequest.Builder(PostNotificationWork.class)
.setInitialDelay(1,TimeUnit.MINUTES)
.build();
WorkManager.getInstance().enqueue(postNotationWithDelay);
}
My worker class
public class PostNotificationWork extends Worker {
#Override
public void onStartWork(#NonNull WorkFinishedCallback callback) {
Log.d("PostNotificationWork: ","onStartWork");//this called many times, some time 4 time
}
#NonNull
#Override
public Result doWork() {
Log.d("PostNotificationWork: ","Posting notification");
return Result.SUCCESS;
}
}
i am using def work_version = "1.0.0-alpha07"
Try to update to this version
def work_version = "1.0.0-alpha06"
implementation "android.arch.work:work-runtime:$work_version"
Remove
#Override
public void onStartWork(#NonNull WorkFinishedCallback callback) {
Log.d("PostNotificationWork: ","onStartWork");//this called many times, some time 4 time
}
Finally Try again
Please do not override onStartWork(). Even if you do you need to call super.onStartWork(). We are still working on the ergonomics of the NonBlockingWorker API.