I'm creating application using PeriodicWorkRequest to execute or fire notification with content changing every day.
it work smoothly but i want to test the content of next day, i search in this case but does not arrive to the best solution. i try to change the day in device but it still does not work
val notificationWorkBuilderRepeated = PeriodicWorkRequest
.Builder(Notification::class.java, 1, TimeUnit.DAYS)
.setInputData(inputData)
.build()
WorkManager.getInstance().enqueue(notificationWorkBuilderRepeated)
The best approach here is to write some androidTest using the WorkManagerTestInitHelper.
This helper makes available a custom driver that you can use to test PeriodicWorkers simulating that the periodic delay has been met:
val testDriver = WorkManagerTestInitHelper.getTestDriver()
// Tells the testing framework the period delay is met
testDriver.setPeriodDelayMet(request.id)
As I have worked for first time with Work Manager I also got this problem for testing.
I have just decreased interval for 15 minutes and tested.
Currently its working fine for every hour.
You can also test it by giving 15 minutes (minimum interval) to test it.
Hope it will helps you. Thank you.
Related
I created a periodic weekly work manager worker to delete the files my application creates.
WorkManager workManager = WorkManager.getInstance(context);
workManager.cancelAllWorkByTag(workTag);
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(DeleteFileWorker.class, 7, TimeUnit.DAYS).addTag(workTag).build();
workManager.enqueueUniquePeriodicWork(workTag, ExistingPeriodicWorkPolicy.REPLACE, periodicWorkRequest);
Here, I'm telling the worker to run once a week or once each 7 days.
But when is it going to run? Can I control the approximate hour?
My guess is it will run the first time it can when the application starts and the second time will be at the same hour(approximately) and day as the first launch.
Can I configure it to run around 12 AM? It doesn't need to be an exact time.
You can't have strong expectations with WM. Please check here the Constraints section:
https://developer.android.com/topic/libraries/architecture/workmanager/how-to/debugging#use-alb-shell0dumpsys-jobscheduler
Also, let me point one thing - what you have "is not" a periodic Work.
What WM does is that it creates a single job in the JobScheduler and it has an extra Constrain - TIMING_DELAY. At the same time besides explicit constraints, you have implicit ones coming from the system. So for a work to be executed all the right conditions need to be in places related to battery optimizations, doze, power buckets, etc. So you can't say for sure when it will happen.
And when the work is executed successfully - WM creates a new job in the JS with TIMING_DELAY again the time you see as a period. So if you put 24 hours as a "period", but the conditions are not right for your work to be executed and it is delayed 10 hours - you will have a 34 hours span between 2 works.
Also, you know it is Android - on every device it is different. But you can improve this by asking your application to be excluded from battery optimization.
https://developer.android.com/training/monitoring-device-state/doze-standby#support_for_other_use_cases
Here more on what to expect from each device:
https://dontkillmyapp.com/
Also, have it in mind that you have a specific amount of time depending on your power bucket to run per day. I guess you are not using Network, but if you do - there is also a set amount of time to use the network. Without battery optimization disabled you might hit some of these:
https://developer.android.com/topic/performance/power/power-details
I've found this weird behaviour of work manger (alpha-12) that it does not execute a job after it was enqueued. The code to enqueue the work is below.
fun enqueue(phoneNumber: String?,priorityId: String? = null): ListenableFuture<WorkInfo> {
return WorkManager.getInstance().run {
val work = OneTimeWorkRequestBuilder<ContentDownloaderWork>()
.addTag(TIMESTAMP)
.setInputData(workDataOf(PHONE to phoneNumber, PRIORITY_ID to priorityId))
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.SECONDS)
.setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
.build()
beginUniqueWork(TIMESTAMP + priorityId.orEmpty(), ExistingWorkPolicy.APPEND, work).enqueue()
getWorkInfoById(work.id)
}
}
I enqueue this work each time on app startup. And what I am doing is killing my app in the middle of the work process that is downloading files from server. It successfully restart every time I reopen my app but for limited number of times.
It seems like it has some sort of queue which gets filled up and does not allow any more jobs to be enqueued. When I check all available jobs by tag it show me that some are canceled and some succeeded but when I try to enqueue a new work it does nothing.
So is it a bug in workmanager or am I doing something wrong?
One important information that is missing in your description is the Android version that you're using in these tests.
WorkManager schedule workers using the JobScheduler API on Android Marshmallow (6.0, API Level 23) and newer, and it schedules a maximum amount of workers using this API at any time (default is 20, maximum is 50). The threshold you're seeing may be linked to this value.
Another important point, is that WorkManager keeps tracks of your workers for you so, if the application is killed while the worker is running, WorkManager automatically restart the worker. You don't need to do anything.
What is not clear to me, is what are you trying to achieve appending a new job every time at the application startup.
Last point, the backoff criteria of 1 second seems a bit aggressive to me. The current default value, looking into the source code, is 30 seconds and the maximum is 5 hours.
However, if you think that there're something wrong (or documented incorrectly) I suggest you to open a bug on WorkManager's public issuetracker.,
I’ve been trying to figure out how to use any of background task APIs in order to create a Work Request that fires every day on a specific time of the day on devices running Android 8.0+.
The time must be set by the user locally on the device (meaning no GCM).
Is that even possible anymore? Legacy devices with AlarmManager works wonders, but as far as I am aware all pending intents are cleared when the app gets Force Stopped so it’s a no go now.
WorkManager's PeriodicWorkRequest doesn't allow you to set the time to start the Work. I looked into creating a delayed OneTimeWorkRequest and schedule the next one after it runs, but nothing ensures that the work will run on the time I want.
Evernote's Android-Job library has issues with the DailyJob too (https://github.com/evernote/android-job/issues/318).
Any suggestions/ideas more than welcome.
New PeriodicWorkRequests now support initial delays. So you take the required time from the user, calculate difference between userTime and Now and just set the delay.
Unlike AlarmManeger it is very reliable.
The only problem is Android fires Worker when it finds the best moment for it (no other work to do), so it may be started with a little delay (usually not more than a few minutes).
You could just use a OneTimeWorkRequest which schedules a copy of itself before it returns a Result.
class TestWorker: Worker() {
fun doWork(): Result {
val nextWorkRequest = OneTimeWorkRequestBuilder<TestWorker>()
nextWorkRequest.withInitialDelay(24, TimeUnit.HOURS)
WorkManager.getInstance().enqueue(nextWorkRequest)
return Result.SUCCESS;
}
}
Start off the first work request with a:
val firstWorkRequest = OneTimeWorkRequestBuilder<TestWorker>()
firstWorkRequest.withInitialDelay(24, TimeUnit.HOURS)
WorkManager.getInstance().enqueue(firstWorkRequest)
Thus you get something which looks like a PeriodicWorkRequest with the timing you need.
Did you try using chained tasks in WorkManager. First Schedule OneTimeWorkRequest, then chain it with PeriodicWorkRequest. Like:
WorkManager.getInstance()
.beginWith(workA)
.then(workB)
where workA is OneTimeWorkRequest and workB is PeriodicWorkRequest
I am working with Android JobScheduler, using a JobInfo.Builder() to launch my Service at a specified time.
Everything works correctly, even when my device enters in sleepmode. But when I restart the device, all the jobs still exist but their delay has been increased, to an astonishing number.
I am creating jobs with specified delay (param minimumLatency) and using the param setPersisited(true) in order to keep the jobs after reboot.
For example let's say I set minimumLatency to 120_000ms.
If I don't reboot my task is correctly executed after the specified delay.
But if I reboot before the task, my mimimumLatency is increased to roughly 40 Billion milli
I have also tried to setOverrideDeadline() to various delays, it des not help
This is how I create the Job:
JobInfo.Builder(id, componentName)
.setExtras(bundle)
.setPersisted(true)
.setMinimumLatency(initialDelay)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.build()
.let {
context.getSystemService(JobScheduler::class.java). schedule(it)
}
Please let me know if you have a clue about this issue.
Any help will be appreciated.
Thanks
I found the issue and a way to solve it. Maybe this will help someone.
It is actually a bug.
When the device boots, in the logs I can see that the device's date is december 31st 2016.
And then, later on when the internet is connected, the system's date is updated to today's date.
So I figured my increased delay is the time between today and Dec. 31st 2016!
I think Android is Starting the JobScheduler service before setting up the date and thus setting them thinking it will be in 1 year and a half.
I guess it depends of the devices. I am on Android TV.
Anyway, this was obviously not directly solvable, so I implemented my own rescheduling in my service and I dont keep the persited parameter.
And doing it this way is actually better for my project and future required customizations.
i want to check network every 1 hour to update data to database from local storage but don't know which one to use either timer or alarm.if you have any code please share with me,thanks is advance.
You can use GcmNetworkManager, it fits the need you described, here is a working sample. It uses JobScheduler internally above 21, and below 21 it uses some Google propriety. You can schedule a periodic task to be run every one hour while adding a pre-condition that internet is required for your task to run. The system will then determine a proper time to run you task. Something like this,
PeriodicTask periodicTask = new PeriodicTask.Builder()
.setService(YOUR_SERVICE) //should extend GcmTaskService
.setPeriod(TimeUnit.HOURS.toSeconds(1))
.setFlex(TimeUnit.MINUTES.toSeconds(30))
.setTag("UpdateDB")
.setRequiredNetwork(PeriodicTask.NETWORK_STATE_CONNECTED)
.setPersisted(true)
.build();
here is a good article explaining the different functionalities provided by GCMNetwork Manager
use background Service and use CountDownTimer in your Service class. and set interval of 1 hour in CountDownTimer