How to compare date with jobscheduler (< Android N) [duplicate] - java

Part of my question, how I can set up a job with less then 15 minutes interval in "Nougat", was answerd by "blizzard" in his answer here:
Job Scheduler not running on Android N
He explained the problem and suggested to use the following workaround:
JobInfo jobInfo;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
jobInfo = new JobInfo.Builder(JOB_ID, serviceName)
.setMinimumLatency(REFRESH_INTERVAL)
.setExtras(bundle).build();
} else {
jobInfo = new JobInfo.Builder(JOB_ID, serviceName)
.setPeriodic(REFRESH_INTERVAL)
.setExtras(bundle).build();
}
However, using the suggested
.setMinimumLatency(REFRESH_INTERVAL)
just starts the job once;
but how do I get it periodic with a period of around 30 seconds on an android nougat device (not using handler or alarm manager)?

If someone is still trying to overcome the situation,
Here is a workaround for >= Android N (If you want to set the periodic job lower than 15 minutes)
Check that only setMinimumLatency is used. Also, If you are running a task that takes a long time, the next job will be scheduled at, Current JOB Finish time + PROVIDED_TIME_INTERVAL
.SetPeriodic(long millis) works well for API Level below Android N
#Override
public boolean onStartJob(final JobParameters jobParameters) {
Log.d(TAG,"Running service now..");
//Small or Long Running task with callback
//Reschedule the Service before calling job finished
if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
scheduleRefresh();
//Call Job Finished
jobFinished(jobParameters, false );
return true;
}
#Override
public boolean onStopJob(JobParameters jobParameters) {
return false;
}
private void scheduleRefresh() {
JobScheduler mJobScheduler = (JobScheduler)getApplicationContext()
.getSystemService(JOB_SCHEDULER_SERVICE);
JobInfo.Builder mJobBuilder =
new JobInfo.Builder(YOUR_JOB_ID,
new ComponentName(getPackageName(),
GetSessionService.class.getName()));
/* For Android N and Upper Versions */
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mJobBuilder
.setMinimumLatency(60*1000) //YOUR_TIME_INTERVAL
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
}
UPDATE:
If you are considering your repeating job to run while in Doze Mode and thinking about JobScheduler, FYI: JobSchedulers are not allowed to run in Doze mode.
I have not discussed about the Dozing because we were talking about JobScheduler. Thanks, #Elletlar, for pointing out that some may think that it will run even when the app is in doze mode which is not the case.
For doze mode, AlarmManager still gives the best solution. You can use setExactAndAllowWhileIdle() if you want to run your periodic job at exact time period or use setAndAllowWhileIdle() if you're flexible.
You can also user setAlarmClock() as device always comes out from doze mode for alarm clock and returns to doze mode again. Another way is to use FCM.
Reference: Doze Restrictions
https://developer.android.com/training/monitoring-device-state/doze-standby

I struggled with same thing when I wanted to setup Job for refresh small part of data. I found out that solution for this problem may be setting up Job one more time with the same ID after i calledjobFinished(JobParameters, boolean). I think it should work every time on main thread.
My function to setup Job looks like this:
JobInfo generateRefreshTokenJobInfo(long periodTime){
JobInfo.Builder jobBuilder = new JobInfo.Builder(1L, new ComponentName(mContext, JobService.class));
jobBuilder.setMinimumLatency(periodTime);
jobBuilder.setOverrideDeadline((long)(periodTime * 1.05));
jobBuilder.setRequiresDeviceIdle(false);
return jobBuilder.build();
}
When I finish my work after first call of Job i call in main thread
jobFinished(mJobParameters, true);
registerRefreshJob(5*60*1000L);
This will reschedule my Job one more time for the same amount of time on the same id. When device is in idle state you still have to take under consideration lack of wake locks in doze so your job may not be started so often as you wish. It is mentioned in https://developer.android.com/about/versions/nougat/android-7.0-changes.html
If the device is stationary for a certain time after entering Doze, the system applies the rest of the Doze restrictions to PowerManager.WakeLock, AlarmManager alarms, GPS, and Wi-Fi scans. Regardless of whether some or all Doze restrictions are being applied, the system wakes the device for brief maintenance windows, during which applications are allowed network access and can execute any deferred jobs/syncs.

Related

Push scheduled notifications when app is not running

First of all: this question is very similar to my last one, but answer couldn't help me...
I am making a To-Do app. I got stuck on pushing notifications (even when app is not running).
My achieve is to push a notification about a to-do task, even if the app is not running.
e.g.
I make a new to-do task about homework on x/y/2021 at mm:hh. App must push a notification at that moment, even while app is not running
Scheduling (delay as 10 is just to debugging):
OneTimeWorkRequest notificationWorker = new OneTimeWorkRequest.Builder(NotificationWorker.class)
.setInitialDelay(10, TimeUnit.SECONDS)
.setInputData(new Data.Builder().putString("title", "Note").build()).build();
WorkManager workManager = WorkManager.getInstance(this);
workManager.enqueue(notificationWorker);
Class extending Worker:
#NonNull
#Override
public Result doWork() {
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
String date = getInputData().getString("date");
String time = getInputData().getString("time");
String title = getInputData().getString("title");
String description = getInputData().getString("description");
int delay = getInputData().getInt("delay", 0);
Notification notification = new NotificationCompat.Builder(getApplicationContext(), "note")
.setSmallIcon(R.mipmap.logo)
.setContentTitle(title)
.setContentInfo(date + " at " + time)
.setContentText(description)
.build();
notificationManager.notify(1, notification);
return Result.success();
}
Honestly i dont read your code but take a look at workManager(because it's designed for these things) :
Android workManager documentation:
WorkManager is an API that makes it easy to schedule deferrable, asynchronous tasks that are expected to run even if the app exits or the device restarts. The WorkManager API is a suitable and recommended replacement for all previous Android background scheduling APIs, including FirebaseJobDispatcher, GcmNetworkManager, and Job Scheduler. WorkManager incorporates the features of its predecessors in a modern, consistent API that works back to API level 14 while also being conscious of battery life.
workManager:https://developer.android.com/topic/libraries/architecture/workmanager
example(i think this is what u want):https://medium.com/#ifr0z/workmanager-notification-date-and-time-pickers-aad1d938b0a3

how to keep alive activity with notification and runnable every second

I have an activity that demonstrates information ping results about servers. This job is done every second with runnable like below code:
pingRunnable = new Runnable() {
#Override
public void run() {
pingMethod();
resultsNotification();
handler.postDelayed(this, 1000);
}
};
on the other hand, I have to show some results in the notification realtime and I did it, But there is a problem, that in the first when the device was locked after 10 min app and activity was destroyed by OS and just notification stopped in a stagnant status. then I tried to fix it with below code:
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
wl.acquire();
wl.release();
Actually, I used wl.release(); like this:
#Override
protected void onDestroy() {
wl.release();
super.onDestroy();
}
It got better when I did it, but when the device was locked this again happened after some hours.
Right now I don't know exactly how can I control these services (background(Runnable) and foreground(Notification) ) together for keeping alive activity for a long time such as two or three days or even more.
First up you shouldn't be using an Activity to do this kind of work a Service is the recommended approach. To do this kind of work intelligently you have a number of options with the Android framework, most recently the new WorkManager component. These services should offer you the ability to control when your background work is scheduled - e.g. only running when a valid network connection is present and by allowing you to select a period when the work should run.
https://developer.android.com/topic/libraries/architecture/workmanager/advanced
Secondly, polling every second will have a drastic impact on battery life - if you do this most likely your app will be flagged as a bad citizen and be a likely candidate for uninstalling.
You should consider whether polling in general is the best option for your users. Using cloud messaging would improve the amount of work your app needs to do to, i.e. you could just push out a notification when the server data changes, which avoids you having to do the manual polling. https://firebase.google.com/docs/cloud-messaging/

How to trigger a JobScheduler when Wifi state changes(connected or disconnected from Network)?

I want to run a piece of code when Wifi is connected or disconnected from some router. I can use service and BrodcastReceiver for this but as of Oreo, the service is killed few minutes after the app is closed (unless in foreground). So, I am trying to use JobScheduler for this but I can't figure out what triggers to provide for execution of my Job.
Android doesn't want to run your code each time there's a network change. These changes may occur several times per minute and your code will cause too much battery drain.
The best you can do is schedule your job to run at regular intervals (which cannot be too short — if you request less than 15 minutes, you won't get it regularly) and check what you need in there. You can request that your job runs only when there's network connectivity, but not the opposite (to run when there's no connectivity).
You can do this perfectly with the Firebase JobDispatcher.
Code to start the job:
fun startNetworkChangeJob() {
// Create a new dispatcher using the Google Play driver.
val dispatcher = FirebaseJobDispatcher(GooglePlayDriver(app))
val myJob = dispatcher.newJobBuilder()
// the JobService that will be called
.setService(NetworkChangeJob::class.java)
// uniquely identifies the job
.setTag(app.getString(R.string.networkChangeJobId))
// recurring job
.setRecurring(true)
// don't persist past a device reboot
.setLifetime(Lifetime.FOREVER)
// start between 0 and 60 seconds from now
.setTrigger(Trigger.executionWindow(0, 60))
// don't overwrite an existing job with the same tag
.setReplaceCurrent(false)
// retry with exponential backoff
.setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
// constraints that need to be satisfied for the job to run
.setConstraints(
// only run on an unmetered network
Constraint.ON_UNMETERED_NETWORK
)
.build()
dispatcher.mustSchedule(myJob)
}
Then the job itself. Here you can place your logic to determine what to do:
override fun onStartJob(job: com.firebase.jobdispatcher.JobParameters): Boolean {
// Runs on the main thread!
checkIfNeedToStartService()
return false // Answers the question: "Is there still work going on?"
}
override fun onStopJob(job: com.firebase.jobdispatcher.JobParameters): Boolean {
// Runs on the main thread!
return true // Answers the question: "Should this job be retried?"
}
Be sure to also add the following to your manifest:
<service
android:name=".jobs.NetworkChangeJob"
android:exported="false">
<intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />
</intent-filter>
</service>

Android Service that run every minute even if my application is closed

I build an application that manage a database of messages and show them to the user, i have a service that basically connect to web server and asks for updates.
I need that service to run every minute even if the application is closed.
so far i wrote the following code:
protected void registerAlarm() {
Intent getUpdatesService = new Intent(this, UpdatesService.class);
PendingIntent sender = PendingIntent.getBroadcast(this, 0, getUpdatesService, 0);
long firstTime = SystemClock.elapsedRealtime();
firstTime += 60 * 1000;
AlarmManager am = (AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, firstTime, 60 * 1000, sender);
}
I call registerAlarm() from an activity that shows the messages.
That suppose to use AlarmManager to run the service evry minute but it doesn't work.
can anyone help me solve the problem?
I need that service to run every minute even if the application is closed.
That will not be practical on Android 6.0 and higher.
can anyone help me solve the problem?
Tactically, your problem is that you are using SystemClock.elapsedRealtime() and RTC_WAKEUP. Those do not match. Use ELAPSED_REALTIME_WAKEUP.
However:
Your app will not get control every minute on Android 6.0+, unless perhaps the user adds your app to the battery optimization whitelist in Settings
AlarmManager does not work at all in some environments, notably the current developer preview of Android apps on Chrome OS (though for all I know this is a bug)
You should use IntentService instead of Service because it automatically terminates after work is done plus it run on background thread

android thread does not run in standby

In my program, I'd like to check for a new version (getting data from HTTP).
The function works perfectly, but I want to have it running in background every X (configurable, one hour, one day, and so on).
So I wrote this code:
Timer mTimer1 = new Timer();
PowerManager pm = (PowerManager) this.main.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = this.pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, MainActivity.PROGRAM);
PowerManager.WakeLock wl.acquire();
TimerTask mTt1 = new TimerTask()
{
public void run()
{
mTimerHandler.post(new Runnable()
{
public void run()
{
// Do the check...
}
});
}
};
(since this function is in a separate class NOT deriving from Activity, I passed to the constructor the parent class this.main, so that I can call getSystemService. This Variable is declared as private MainActivity main).
Well, when I start the Timer it checks for new version, then, after an hour (so my settings), I check in the Logs and I see that the thread did not run...
I searched in Internet and I found, that I have to use the PARTIAL_WAKE_LOCK, and I do that...
Any idea, why I have this problem?
Thanks a lot!
Luca Bertoncello
Here is a SO answer that can help you with this using a handler and postDelayed().
However, if you want to run this even when the app isn't open then you will want to use an AlarmManger.You create a PendingIntent and create a Calendar instance to set the time you want it to check then use setRepeating() on the AlarmManger. This will have it check even when not in the app. You can also register it in the manifest as Boot_Completed so it will start running again after reboot when the device is turned off
Here is a good example to get you started with AlarmManager
If you are using a Timer, did you remember to schedule your TimerTask?
Try
mTimer1.schedule(mTt1, delay, interval);
And if you want to stop that, do mTimer1.cancel();
and mTimer1.purge(); to clear the schedule queue.
When the phone goes to sleep, execution will be paused for your activity and thus your timer will never fire. Using PARTIAL_WAKE_LOCK is probably not a good idea as it will consume battery the entire time your phone sleeps.
I would suggest taking a look at AlarmManager and specifically setInexactRepeating
Use this code
Timer timer = new Timer();
timer.scheduleAtFixedRate(
new java.util.TimerTask() {
#Override
public void run() {
// Your code
}},
1000, 5000
);
Where 1000 is a post delay , if you want delay for first time , if you don't want than put it 0
5000 is a iteration time

Categories

Resources