how to run a job service at a given time - android

i want to create something like a reminder app which notify user at given times
, i want to use job scheduler api to achieve this let's say i want to run the service at 9 am and 12 am what should be added in the following code to achieve this.
public void startJobService(){
GooglePlayDriver driver = new GooglePlayDriver(this);
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(driver);
Bundle myExtrasBundle = new Bundle();
myExtrasBundle.putString("some_key", "some_value");
Job myJob = dispatcher.newJobBuilder()
.setService(jobservice.class)
.setTag("unique-tag")
.setExtras(myExtrasBundle)
.build();
dispatcher.mustSchedule(myJob);
}
//this is the JobService class
public class jobservice extends JobService{
private static final String TAG = "jobservice";
#Override
public boolean onStartJob(JobParameters job) {
Log.d(TAG, "onStartJob: "+job.getExtras());
return true;
}
#Override
public boolean onStopJob(JobParameters job) {
return false;
}
}

Unfortunately it seems that the JobService does not provide this api. Two things you can do:
Use Alarm Manager to trigger the job service when you want or
Run you job service frequent (let's say once per hour). Then check if the current time is on your desired interval. If yes proceed, if no abort the job.
For example:
final Job job = dispatcher.newJobBuilder()
.setService(MyService.class)
.setTag(MyService.class.getName())
.setRecurring(true)
.setLifetime(Lifetime.FOREVER)
.setTrigger(Trigger.executionWindow(HOUR, 2 * HOUR))
.setReplaceCurrent(false)
.setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
.build();
And then inside your Job Service:
#Override
public boolean onStartJob(JobParameters job) {
if (!nowIsInDesiredInterval()) {
Timber.i("Now is not inside the desired interval. Aborting.");
return false;
}
// else execute your job
// .....
return false;
}

Related

Firebase job service started with big delay

I am testing an application that receives Firebase cloud data messages and processes them in the Firebase job service. Receiving messages in the FirebaseMessagingService occurs instantly and without problems, but the Firebase job service sometimes starts with a long delay (5-10 minutes), and sometimes it does not start at all. The dispatcher.schedule (myJob) method always gives the result SCHEDULE_RESULT_SUCCESS. This is the job scheduling functionality:
// For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
Bundle bundle = new Bundle();
bundle.putInt(WatchDogService.REQUEST_ID, request.ordinal());
bundle.putString(REQUEST_PARAM, parameter);
FirebaseJobDispatcher dispatcher =
new FirebaseJobDispatcher(new GooglePlayDriver(this));
Job myJob = dispatcher.newJobBuilder()
.setService(LongJobService.class)
.setTag("ua.ers.LongJobService")
.setTrigger(Trigger.NOW)
.setReplaceCurrent(true)
.setExtras(bundle)
.build();
int result = dispatcher.schedule(myJob);
Log.d(TAG, "Schedule result: " + result);
Here is a Firebase Job Service class:
public class LongJobService extends JobService {
private static final String TAG = "LongJobService";
#Override
public boolean onStartJob(final JobParameters jobParameters) {
Log.d(TAG, "LongJobService started");
return true;
}
#Override
public boolean onStopJob(JobParameters jobParameters) {
Log.d(TAG, "LongJobService stopped");
return false;
}
}
Tell me, please, what could be the cause of the problem?
According to documentation, this is just the usual behaviour
The scheduler backend is encouraged to use the windowEnd value as a signal that the job should be run, but this is not an enforced behavior.
But for a better execution try
Trigger.executionWindow(0, 0)
instead of
Trigger.NOW
So it will look like
Job myJob = dispatcher.newJobBuilder()
.setService(Service.class)
.setRecurring(true) // if task is periodic, else pass "false"
.setTrigger(Trigger.executionWindow(0, 0))
.setTag("tag")
.build();

Firebase Job Dispatcher not Scheduling jobs on OREO devices

I have a firebase job dispatcher which is scheduled to run whenever network changes ,the job is working perfectly on a marshmallow device (23 API level) but the same code when run is not scheduling jobs on a oreo device(26 API level)
Here is my Job Service code:
public class MyJobService extends JobService {
#Override
public boolean onStartJob(JobParameters job) {
Log.d("Executing","Job");
Realm realm = Realm.getDefaultInstance();
RealmResults<JsontoSend> realmResults = realm.where(JsontoSend.class).findAll();
if(!realmResults.isEmpty()) {
for (JsontoSend jsontoSend : realmResults) {
final Intent intent = new Intent(getApplicationContext(), PostUploadIntentService.class);
intent.putExtra("object", jsontoSend.getJson());
new Thread(new Runnable() {
#Override
public void run() {
startService(intent);
}
}).run();
}
}
return true;
}
#Override
public boolean onStopJob(JobParameters job) {
Log.d("instopjob","cancelled");
return true;
}
}
This is my code where i have created the job :
synchronized public static void schedule(#NonNull final Context context){
if(sInitialized)
return;
Driver driver=new GooglePlayDriver(context);
FirebaseJobDispatcher dispatcher=new FirebaseJobDispatcher(driver);
Job myJob = dispatcher.newJobBuilder()
.setService(MyJobService.class)
.setTag(JOB_TAG)
.setRecurring(true)
.setTrigger(Trigger.executionWindow(5, 60))
.setLifetime(Lifetime.FOREVER)
.setConstraints(Constraint.ON_ANY_NETWORK)
.setReplaceCurrent(false)
.setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
.build();
dispatcher.schedule(myJob);
sInitialized=true;
}
What i am trying to do is if i do not have internet connection then storing the data in local database and then running a job whenever i connect to internet and sync the data with server .The above code is working perfectly on marshmallow device but the job is never scheduled on oreo devices.
well the problem here is probably because you use GooglePlayDriver which relies on google play services to be presented on the devices. If the services are not available the job will not be scheduled.
So if you target on devices higher than 5.0 (which is true in most cases) you have to use android's JobScheduler build in since lollipop.

Perform REST call from background in android after fixed interval

I am new to Android, I want to know the most efficient way to perform a background operation which is a simple POST request with JSON Body which will be hit after a fixed interval. Which is best way, Intent Service Or Async Task.
Create a JobScheduler as below
public static void scheduleJob(Context context) {
ComponentName serviceComponent = new ComponentName(context, TestJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(0, serviceComponent);
builder.setMinimumLatency(1 * 1000); // wait at least
builder.setOverrideDeadline(3 * 1000); // maximum delay
charging or not
JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
jobScheduler.schedule(builder.build());
}
Create the following receiver
public class MyStartServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Util.scheduleJob(context);
}
}
Register the receiver in the Android manifest for the BOOT_COMPLETED event.
<receiver android:name="MyStartServiceReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Create a JobService and add your code in to onStartJob
public class TestJobService extends JobService {
private static final String TAG = "SyncService";
#Override
public boolean onStartJob(JobParameters params) {
Intent service = new Intent(getApplicationContext(), LocalWordService.class);
getApplicationContext().startService(service);
Util.scheduleJob(getApplicationContext()); // reschedule the job
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
return true;
}
}
For more details refer : linkhere
Please refer this link: https://developer.android.com/reference/java/util/concurrent/ScheduledExecutorService
Please check my custom class example below. This will execute every 2 seconds.
class CustomThreadExecutor {
private lateinit var scheduledExecutorService: ScheduledExecutorService
private lateinit var scheduledFuture: ScheduledFuture<*>
init {
//Start Scheduler as required
startScheduler()
}
fun startScheduler() {
scheduledExecutorService = Executors.newScheduledThreadPool(2)
scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(
{ tempImageFetch() }, 0, 2, TimeUnit.SECONDS)
}
fun shutdownScheduler() {
//Stop before exit the app or when necessary
scheduledExecutorService.shutdownNow()
}
private fun tempImageFetch() {
//TODO call API
}
}
You can use FirebaseJobDispatcher for API level below and above Lollipop. Here is the github link:
https://github.com/firebase/firebase-jobdispatcher-android
How to implement:
Add the following to your build.gradle's dependencies section:
implementation 'com.firebase:firebase-jobdispatcher:0.8.5'
Make a class for your job service:
public class MyJobService extends JobService {
#Override
public boolean onStartJob(JobParameters job) {
// Do some work here
return false; // Answers the question: "Is there still work going on?"
}
#Override
public boolean onStopJob(JobParameters job) {
return false; // Answers the question: "Should this job be retried?"
}
}
Add this on Manifest:
<service
android:exported="false"
android:name=".MyJobService">
<intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE"/>
</intent-filter>
</service>
Add this on your main activity onCreate method:
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context));
Bundle myExtrasBundle = new Bundle();
myExtrasBundle.putString("some_key", "some_value");
Job myJob = dispatcher.newJobBuilder()
// the JobService that will be called
.setService(MyJobService.class)
// uniquely identifies the job
.setTag("my-unique-tag")
// one-off job
.setRecurring(false)
// don't persist past a device reboot
.setLifetime(Lifetime.UNTIL_NEXT_BOOT)
// 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,
// only run when the device is charging
Constraint.DEVICE_CHARGING
)
.setExtras(myExtrasBundle)
.build();
dispatcher.mustSchedule(myJob);
If your application is for API level Lollipop and above, then you should use JobScheduler or WorkManager
For workmanager:
https://codelabs.developers.google.com/codelabs/android-workmanager/
For JobScheduler:
http://www.vogella.com/tutorials/AndroidTaskScheduling/article.html

Cant stop Firebase JobDispatcher service

Possible Duplicate
I have created a JobDispatcher service to keep getting user location in background and post user location to server. For that i have created a Job as follow:
private void startLocationJobService() {
// Check if location job service already running
if(!isMyServiceRunning(LocationJobService.class)) {
Context context = config.getActivity();
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context));
Job job = dispatcher.newJobBuilder()
.setLifetime(Lifetime.FOREVER)
.setService(LocationJobService.class)
.setTag(JOB_SERVICE_TAG)
.setReplaceCurrent(true)
.build();
//creating new job and adding it with dispatcher
dispatcher.mustSchedule(job);
}
}
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) config.getActivity().getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
In service's onStartJob i am configuring location api to get user location
public boolean onStartJob(final JobParameters job) {
Log.i("TAG", "Service Run onStartJob called");
configureFusedLocation(LocationJobService.this);
return true;
}
Service starts and keep running as expected. But it does not stop. I have used both ways (dispatcher.cancel and stopService) to stop service as follow:
public void stopService() {
if(isMyServiceRunning(LocationJobService.class)) {
config.getActivity().stopService(new Intent(config.getActivity(), LocationJobService.class));
cancelLocationJobService();
}
}
private void cancelLocationJobService(){
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(config.getActivity()));
// Cancel the job for this tag
dispatcher.cancel(JOB_SERVICE_TAG);
//Cancel all the jobs for this package
dispatcher.cancelAll();
}
you need to cancel job in itself by unregistering location listener and calling jobFinished() inside LocationJobService.
As dispatcher.cancelAll() works only to cancel scheduled jobs which are yet to be run.
You may use tools like Eventbus to inform service when to stop.
Refer https://medium.com/google-developers/scheduling-jobs-like-a-pro-with-jobscheduler-286ef8510129 for more info.

android: scheduling job every hour forever

I have a web service on my server that needs to be pinged every hour. For this, I am using an Android app to ping it every hour. I have tried using Alarm manager but it stops working after few hours and if I swipe exit it. I have tried using service but for some reason, that doesn't seem to work and my app keeps crashing. I have am thinking about using Firebase Job dispatcher. My requirement is that the app needs to ping the web service on my server every hour. This should go on for at least next 3-4 months. Is there a way to accomplish this ? Thanks in advance!
EDIT: I have tried broadcast receiver with Alarm Manager but have not been able to sustain the firing for more then 4 hours.
I second Anantha's answer but seems like job parameters are little off for your needs.
You can go over this article to learn about the subtle differences between various Job schedulers.
As a matter of fact, even Google recommends using Firebase Job Schedular if the app needs to do a network communication due to various reasons. Please watch the attached video on the Github page for more info on the same. This also gives you basic code to kickstart your application. You can just change the job parameters to suit your needs
Hopefully, this below code should suit your requirement of triggering every one hour with a tolerance of 15 minutes
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(getContext()));
final int periodicity = (int)TimeUnit.HOURS.toSeconds(1); // Every 1 hour periodicity expressed as seconds
final int toleranceInterval = (int)TimeUnit.MINUTES.toSeconds(15); // a small(ish) window of time when triggering is OK
Job myJob = dispatcher.newJobBuilder()
// the JobService that will be called
.setService(yourJobService.class)
// uniquely identifies the job
.setTag("my-unique-tag")
// recurring job
.setRecurring(true)
// persist past a device reboot
.setLifetime(Lifetime.FOREVER)
// start between 0 and 60 seconds from now
.setTrigger(Trigger.executionWindow(periodicity, toleranceInterval))
// overwrite an existing job with the same tag
.setReplaceCurrent(true)
// 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_ANY_NETWORK
)
.setExtras(schedulerextras)
.build();
dispatcher.mustSchedule(myJob);
Jhon you can use firebase jobdispatcher. because it will support from api level 9. you can see below how to create job dispatcher and how to call it.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
scheduleJob(this);
}
public static void scheduleJob(Context context) {
//creating new firebase job dispatcher
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context));
//creating new job and adding it with dispatcher
Job job = createJob(dispatcher);
dispatcher.mustSchedule(job);
}
public static Job createJob(FirebaseJobDispatcher dispatcher){
Job job = dispatcher.newJobBuilder()
//persist the task across boots
.setLifetime(Lifetime.FOREVER)
//.setLifetime(Lifetime.UNTIL_NEXT_BOOT)
//call this service when the criteria are met.
.setService(ScheduledJobService.class)
//unique id of the task
.setTag("UniqueTagForYourJob")
//don't overwrite an existing job with the same tag
.setReplaceCurrent(false)
// We are mentioning that the job is periodic.
.setRecurring(true)
// Run between 30 - 60 seconds from now.
.setTrigger(Trigger.executionWindow(30, 60))
// retry with exponential backoff
.setRetryStrategy(RetryStrategy.DEFAULT_LINEAR)
//.setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
//Run this job only when the network is available.
.setConstraints(Constraint.ON_ANY_NETWORK, Constraint.DEVICE_CHARGING)
.build();
return job;
}
public static Job updateJob(FirebaseJobDispatcher dispatcher) {
Job newJob = dispatcher.newJobBuilder()
//update if any task with the given tag exists.
.setReplaceCurrent(true)
//Integrate the job you want to start.
.setService(ScheduledJobService.class)
.setTag("UniqueTagForYourJob")
// Run between 30 - 60 seconds from now.
.setTrigger(Trigger.executionWindow(30, 60))
.build();
return newJob;
}
public void cancelJob(Context context){
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context));
//Cancel all the jobs for this package
dispatcher.cancelAll();
// Cancel the job for this tag
dispatcher.cancel("UniqueTagForYourJob");
}}
ScheduledJobService.java
public class ScheduledJobService extends JobService {
private static final String TAG = ScheduledJobService.class.getSimpleName();
#Override
public boolean onStartJob(final JobParameters params) {
//Offloading work to a new thread.
new Thread(new Runnable() {
#Override
public void run() {
codeYouWantToRun(params);
}
}).start();
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
return false;
}
public void codeYouWantToRun(final JobParameters parameters) {
try {
Log.d(TAG, "completeJob: " + "jobStarted");
//This task takes 2 seconds to complete.
Thread.sleep(2000);
Log.d(TAG, "completeJob: " + "jobFinished");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//Tell the framework that the job has completed and doesnot needs to be reschedule
jobFinished(parameters, true);
}
}}
You will need to use JobScheduler(api >21 ) and GcmNetworkManager (api<21) depending on the api level of android. Check out this library from evernote which takes care of it.
Do you try broadcast receiver? I use Broadcast Receiver with Alarm Manager to vibrate every minute and it work fine. The only problem is that when device turn off or restarted, it not vibrate till I enter my application.
My test code.
public void setAlarm() {
alarmMgr =(AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(AlarmManagerActivity.this, AlarmManagerBroadcastReceiver.class);
intent.setAction("a.b.c.d");
PendingIntent pi = PendingIntent.getBroadcast( getApplicationContext(), 0, intent, 0);
//After after 5 seconds
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 13);
calendar.set(Calendar.MINUTE, 40);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis()
, (1000) * (60)
, pi);
}
My receiver
#Override
public void onReceive(Context context, Intent intent) {
Log.d(getClass().getSimpleName(), Intent.ACTION_BOOT_COMPLETED);
if ( intent.getAction().equals("a.b.c.d")) {
Log.d(getClass().getSimpleName(), "Custom Broadcast01");
Vibrator vibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(10000);
}
else
Log.d(getClass().getSimpleName(), "no this action for intent!");
}
Broadcast receiver to start Alarm when device restart
<receiver
android:name=".OnBootBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class OnBootBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
setAlarm();
}
}

Categories

Resources