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.
Related
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();
I want to know whether the following method will work or not, I've got this method in stack-overflow itself but it doesn't seem to work.
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
I have a Job Service, which will be executed every 15 minutes for this the I am using Job scheduler to trigger the service with whatever time is mentioned.
I have a method as executeService() as follows:
public JobScheduler initJob(Context context){
if(jobScheduler == null){
jobScheduler = (JobScheduler)context.getSystemService(JOB_SCHEDULER_SERVICE);
}
return jobScheduler;
}
public void executeService(){
initJob(this);
ComponentName jobService = new ComponentName(this.getPackageName(), OfflineService.class.getName());
JobInfo jobInfo = new JobInfo.Builder(2,jobService).
setPersisted(true).
setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).
setPeriodic(millisecondsQueue).
build();
int jobId = jobScheduler.schedule(jobInfo);
}
Now this executeService() is called every time the user comes to MainActivity, onResume of MainActivity I've put a check as below
if(!isMyServiceRunning(OfflineService.class)){
executeService();
}
If my service is already triggered then after I come back to MainActivity the method isMyServiceRunning() returns false always.
I've gone through all the questions-answers related to this but I ended up writing this question again I am using Android OS Nougat.Any help would be great.
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.
My app is targeting Android 7, with minimum SDK Android 4.
Hence, listening to CONNECTIVITY_CHANGE (Even when the app is killed) no longer work anymore. What I wish to do is
Even when my main app is killed, when the internet connectivity change from "not available" to "available", I would like to start an alarm broadcast receiver.
I try to achieve with the following code
MainActivity.java
#Override
public void onPause() {
super.onPause();
installJobService();
}
private void installJobService() {
// Create a new dispatcher using the Google Play driver.
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this));
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(true)
// persist forever
.setLifetime(Lifetime.FOREVER)
// start between 0 and 60 seconds from now
.setTrigger(Trigger.executionWindow(0, 60))
// 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 any network
Constraint.ON_ANY_NETWORK
)
.build();
dispatcher.mustSchedule(myJob);
}
However,
MyJobService.java
import android.content.Context;
import com.firebase.jobdispatcher.JobParameters;
import com.firebase.jobdispatcher.JobService;
import org.yccheok.jstock.gui.JStockApplication;
/**
* Created by yccheok on 21/5/2017.
*/
public class MyJobService extends JobService {
#Override
public boolean onStartJob(JobParameters jobParameters) {
Context context = this.getApplicationContext();
android.util.Log.i("CHEOK", "Internet -> " + Utils.isInternetAvailable(context));
// Answers the question: "Is there still work going on?"
return false;
}
#Override
public boolean onStopJob(JobParameters jobParameters) {
// Answers the question: "Should this job be retried?"
return true;
}
}
However, the above code isn't reliable. How I test is
Quit my app.
Kill my app explicitly via Settings using "Force stop".
Turn off internet.
Turn on internet.
Wait for few minutes. MyJobService is never executed.
Is there any reliable way, to use FirebaseJobDispatcher to replace CONNECTIVITY_CHANGE reliably?
I had gone through Firebase JobDispatcher - how does it work compared to previous APIs (JobScheduler and GcmTaskService)? , but I still can't find a way to make it work reliably.
Not sure how you are detecting CONNECTIVITY_CHANGE through FirebaseJobDispatcher but for same situation I had used broadcast
public class ConnectivityStateReceiver extends BroadcastReceiver {
String TAG = "MyApp";
#Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context, NetworkService.class);
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm == null) {
return;
} else if (cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected()) {
Log.e(TAG, "Connected!");
context.startService(serviceIntent);
} else {
Log.e(TAG, "Not Connected!");
context.stopService(serviceIntent);
}
}
}
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;
}