I am trying to upload to data to a server in background when there are internet and app is not running in the front end.
So I read somewhere this can be achieved by JobService.
I created a simple job service that toasts onStartJob and in the splash screen activity. I called the below code:
mJobScheduler = (JobScheduler)
getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo.Builder builder = new JobInfo.Builder(1,
new ComponentName(getPackageName(),
Unigen_Upload_JobScheduler.class.getName()));
builder.setPeriodic(60000);
builder.setPersisted(true);
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
if (mJobScheduler.schedule(builder.build()) <= 0) {
Log.e("Value", "onCreate: Some error while scheduling the job");
}
This runs the first time properly but doesn't run again after 1 minute. I am not sure why this isn't happening?
Also, I had another question will this trigger whenever the WIFI or Mobile is switched ON / Changed?
Do I have to use a broadcast receiver to do the above?
Thanks!
Update:
public class Unigen_Upload_JobScheduler extends JobService {
public Unigen_Upload_JobScheduler() {
}
#Override
public boolean onStartJob(JobParameters params) {
Toast.makeText(this,"Executed",Toast.LENGTH_LONG).show();
Log.e("Value","+_ what should I do");
/*
* True - if your service needs to process
* the work (on a separate thread).
* False - if there's no more work to be done for this job.
*/
return false;
}
#Override
public boolean onStopJob(JobParameters params) {
return false;
}
}
The minimum interval for JobScheduler Periodic Job is 15 minutes. Check the reason behind this:
Why can't an interval be smaller than 15 minutes for periodic jobs?
JobScheduler's minimum periodic interval is 15 minutes or (15 * 60 * 1000) 900000ms. You can look into WorkManager which is a part of android jetpack for more convenient usage. As for your second question workmanager has convenient methods for scheduling tasks on various scenarios.
Related
I want to sync data to server after certain amount of time and this time is configurable ranging from 30 minutes to 8 hours.
I am using JobScheduler to achieve above.
Is there any way using which I can update the JobInfo associated with JobScheduler?
So that I can update value set in setPeriodic(intervalMillis) method to the updated time interval.
Refer my sample code below
int PERIODIC_SYNC_JOB_ID = 0;
long interval = 1000 * 60 * 20;
JobInfo.Builder builder = new JobInfo.Builder(PERIODIC_SYNC_JOB_ID,
new ComponentName(getApplicationContext(), SampleJobService.class));
JobInfo jobInfo = builder.setPeriodic(interval).build();
JobScheduler jobScheduler = (JobScheduler) getApplicationContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(jobInfo);
Log.d("JobScheduler", "Sample job is scheduled every " + interval + " ms");
SampleJobService.java
public class SampleJobService extends JobService {
#Override
public boolean onStartJob(JobParameters jobParameters) {
Log.d("SampleJobService", "onStartJob()");
// do something in another thread/handler/AsyncTask
jobFinished(jobParameters, false);
Log.d("SampleJobService", "Sample job is rescheduled");
return true;
}
#Override
public boolean onStopJob(JobParameters jobParameters) {
Log.d("SampleJobService", "onStopJob()");
return false;
}
}
Remember to add your service in Manifest
<service
android:name=".SampleJobService"
android:permission="android.permission.BIND_JOB_SERVICE" />
Note that minimum interval is 15 minutes. Attempting to declare a smaller period that this when scheduling a job will result in a job that is still periodic, but will run with this effective period.
I am trying to download some file in background. Earlier i was doing with intent service, and my app wont get freezed in using intent service. But as with oreo and above versions onward Intent service is getting destroyed as soon as app get closed from background. Same processing i did it in a Job service but it seem its running on main thread. What should i do for background processing that shouldn't be running on main thread ?
Below is code for JOB scheduling i did:
public class Util {
// schedule the start of the service every 10 - 30 seconds
#TargetApi(Build.VERSION_CODES.M)
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public static void scheduleJob(Context context) {
ComponentName serviceComponent = new ComponentName(context, MyService.class);
JobInfo.Builder builder = new JobInfo.Builder(0, serviceComponent);
builder.setMinimumLatency(1 * 1000); // wait at least
builder.setOverrideDeadline(3 * 1000); // maximum delay
//builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); // require unmetered network
//builder.setRequiresDeviceIdle(true); // device should be idle
//builder.setRequiresCharging(false); // we don't care if the device is charging or not
JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
jobScheduler.schedule(builder.build());
}
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class MyService extends JobService {
private static final String TAG = "SyncService";
public Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
public SharedPreferences sharedPreferences;
public ComplexObject complexObject;
private Context context;
public static final String NOTIFICATION_CHANNEL_ID = "10001";
#Override
public boolean onStartJob(JobParameters params) {
System.out.println("RUnning this Job.......");
context = this;
this.sharedPreferences = context.getSharedPreferences(context.getResources().getString(R.string.shared_preference_key), Context.MODE_PRIVATE);
//30-40 HTTP call to process the data
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
return true;
}
Not sure if this will help you since it's kinda old but:
Your title reads JobIntentService and you use JobService, the answer by
TheWanderer refers to your used class (JobService), but if you will use JobIntentService, its method onHandleWork runs on a background thread:
This method is called on a background thread, so you can do long blocking operations here.
According to the docs:
This service executes each incoming job on a Handler running on your application's main thread. This means that you must offload your execution logic to another thread/handler/AsyncTask of your choosing. Not doing so will result in blocking any future callbacks from the JobManager - specifically onStopJob(android.app.job.JobParameters), which is meant to inform you that the scheduling requirements are no longer being met.
So, you'll need to use an AsyncTask or some other form of asynchronous method to execute your logic. You should use something cancellable, though, since, when onStopJob() is called, you're supposed to stop whatever you're doing.
Also remember to call jobFinished() when your logic has been completed.
You can use JobIntentService as a solution to download/upload some file or even communicate with server. One another good even better approach is WorkManager. Note that IntentService runs on UI thread that is the onHandleIntent(Intent intent) runs on UI thread. So we should use a separate Thread or use of for example AsyncTask. But JobIntentService has the function onHandleWork(#NonNull Intent intent) which is run on a background thread and so we just do the work on it. In WorkManager approach, the work is done in doWork() method of Worker and this function also runs on a background thread and so we should write the main code inside it. I think JobIntentService and WorkerManager are both good for such purpose. JobIntentService just runs the work once, but by WorkManager we can do a work once or repeat it periodically (the interval time between periods has a minimum of 15 minutes).
I am using JobScheduler in my application. I want to upload file after every hour if user connected to WIFI, but onStartJob()method gets called before hour, mostly it gets called after 15-20 min. Following is my code :
ComponentName componentName = new ComponentName(this,UploadService.class);
JobInfo info = new JobInfo.Builder(1,componentName)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) // change this later to wifi
.setPersisted(true)
.setPeriodic(60*60*10000)
.build();
JobScheduler scheduler = (JobScheduler)getSystemService(JOB_SCHEDULER_SERVICE);
int resultCode = scheduler.schedule(info);
if (resultCode==JobScheduler.RESULT_SUCCESS) {
Log.d(TAG,"JOb Scheduled");
} else {
Log.d(TAG,"Job Scheduling fail");
}
public class UploadService extends JobService {
#Override
public boolean onStartJob(JobParameters params) {
uploadFileToServer(params);
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
return true;
}
.....
.....
}
Here uploadFileToServer(params); gets called before hour. how to set time so it will call only after hour. Thanks in advance
Use this method setPeriodic (long intervalMillis, long flexMillis) (Added in API 24) on the JobInfo.Builder and supply a flex interval as the 2nd parameter:
long flexMillis = 59 * 60 * 1000; // wait 59 minutes before executing next job
JobInfo info = new JobInfo.Builder(1,componentName)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) // change this later to wifi
.setPersisted(true)
.setPeriodic(60 * 60 * 1000, flexMillis)
.build();
Importent - The job is guaranteed to run after the flex interval (which starts after the last job is finished), but it's not guaranteed to run immediately after that time, so the duration between jobs can be more than 1 hour, depending on your job requirements, system status, and more...
Docs ref: https://developer.android.com/reference/android/app/job/JobInfo.Builder.html#setPeriodic(long,%20long)
Specify that this job should recur with the provided interval and flex. The job can execute at any time in a window of flex length at the end of the period.
As already recommended in some comments, you should start working with the new WorkManager (even that it's not production level yet) which has similar features as the JobScheduler, but it's minimum SDK support is 14 which will let you delete a lot of boilerplate code :)
From the JobInfo.java class ,
You have no control over when within this interval this job will be executed
/**
* Specify that this job should recur with the provided interval, not more than once per
* period. You have no control over when within this interval this job will be executed,
* only the guarantee that it will be executed at most once within this interval.
* Setting this function on the builder with {#link #setMinimumLatency(long)} or
* {#link #setOverrideDeadline(long)} will result in an error.
* #param intervalMillis Millisecond interval for which this job will repeat.
*/
public Builder setPeriodic(long intervalMillis) {
return setPeriodic(intervalMillis, intervalMillis);
}
My code is work. But I'm not sure that this will work on all devices and always.
Can I use JobScheduler like this?
Start method:
public static void schedule() {
JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo job = new JobInfo.Builder(1, new ComponentName(context, MySchedulerService.class))
.setMinimumLatency(15000)
.build();
scheduler.schedule(job);
}
Service:
public static class MySchedulerService extends JobService {
public boolean onStartJob(JobParameters params) {
schedule();
/* Business code */
stopSelf();
return false;
}
public boolean onStopJob(JobParameters params) {
return false;
}
}
Can I schedule job every 15 seconds
No. Minimum duration between two schedule is around 15 minutes. You can easily query for this information using getMinPeriodMillis()
Note:
Attempting to declare a smaller period that this when scheduling a job
will result in a job that is still periodic, but will run with this
effective period.
For setMinimumLatency, based on the documentation:
Milliseconds before which this job will not be considered for
execution.
This doesn't mean the job will be executed immediately after 15 seconds and won't be reliable from Android N when first phase of doze mode kicks in.
I'm trying to implement background refreshing service with new JobScheduler(compat by tatarka).
Here is my Service
#Override
public boolean onStartJob(JobParameters params) {
Timber.i("on start job: " + params.getJobId());
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
Timber.i("on stop job: " + params.getJobId());
return true;
}
Here is my JobInfo
public void scheduleJob(View v) {
JobInfo job = new JobInfo.Builder(kJobId++ /*jobid*/, new ComponentName(getActivity(), RefreshJobService.class))
.setPeriodic(2000)
.build();
mTestService.scheduleJob(job);
}
In log i see that my job always works for 1 minute
12-31 12:38:03.884 10059-10059/#/RefreshJobService﹕ on stop job: 0
12-31 12:39:03.891 10059-10059/#/RefreshJobService﹕ on start job: 0
12-31 12:40:03.911 10059-10059/#/RefreshJobService﹕ on stop job: 0
12-31 12:42:08.841 10059-10059/#/RefreshJobService﹕ on start job: 0
12-31 12:43:08.858 10059-10059/#/RefreshJobService﹕ on stop job: 0
So why? I'm set periodic to 2000ms, any value do not influence to 1 minute interval for job. Why?
Until Android 5.1.1 there was a timeout of 60 seconds for a single job. Starting from Android 6, the timeout is now of 10 minutes.
onStopJob is called when the system wants to cancel your job. The reason it is cancelling your job is because it thinks it's still running. You need to call jobFinished(params, bool) at some point in your job to tell the scheduler that it is complete, otherwise it will time out and call onStopJob to cancel it. In addition, returning 'true' from onStartJob tells the system that you are not done processing. You should return 'false' unless you are still doing extra work, eg. passing the work off to a separate thread.
#Override
public boolean onStartJob(JobParameters params) {
Timber.i("on start job: " + params.getJobId());
jobFinished(params, false);
return false;
}
From API 26 (Oreo), setting a smaller period than 15 minutes for periodic jobs will execute at least after 15 minutes.
It sounds like you are asking why is it that you get onStopJob exactly one minute after your job is started.
This 1 minute timeout is defined in code here
43matthew is correct, but I'd like to add something more to this. The 2000 ms that you're talking about is the periodic interval after which the job starts again i.e. execute this job every 2000 ms, not the interval for which the job will execute.