Reputation: 3347
I have a fused location provider code in MainActivity class providing latitude and longitude values, which is passed to JobService class using persistableBundle. It works fine when the user is using the app (ie. app is in foreground). As soon as the app is swiped out or destroyed, the last updated value from MainActivity is repeatedly uploaded through the job scheduler all the time (ie. the jobscheduler gets the same value all the time, the fused location provider don't work). What should I do to make it work even if the app is not in the foreground? (PS. it works when the app is minimized. ie. it can be seen in recent app list but the problem occurs as soon as it is swiped out from the list)
MainActivity.class
public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// JobScheduler starts
btnStartJob = (Button)findViewById(R.id.startjob);
jobScheduler = (JobScheduler)getSystemService(JOB_SCHEDULER_SERVICE);
btnStartJob.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
ComponentName jobService =
new ComponentName(getPackageName(), MyJobService.class.getName());
PersistableBundle bundle = new PersistableBundle();
bundle.putString("lat", latitude+"");
bundle.putString("lon", longitude+"");
JobInfo jobInfo =
new JobInfo.Builder(MYJOBID, jobService).setPeriodic(10000).
setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).
setRequiresCharging(false).
setRequiresDeviceIdle(false).
setPersisted(true).
setExtras(bundle).
build();
int jobId = jobScheduler.schedule(jobInfo);
if(jobScheduler.schedule(jobInfo)>0){
}else{
}
}
});
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
private boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, this,
PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Toast.makeText(getApplicationContext(),
"This device is not supported.", Toast.LENGTH_LONG)
.show();
finish();
}
return false;
}
return true;
}
@Override
public void onConnected(Bundle bundle) {
createLocationRequest(bundle);
}
protected void createLocationRequest(Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, new LocationCallback() {
@Override
public void onLocationResult(final LocationResult locationResult) {
latitude = locationResult.getLastLocation().getLatitude() + "";
longitude = locationResult.getLastLocation().getLongitude() + "";
Log.e("onLocationResult lat", latitude);
Log.e("onLocationResult Lon", longitude);
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
}
}, null);
}
@Override
public void onConnectionSuspended(int i) {
mGoogleApiClient.connect();
}
@Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = "
+ result.getErrorCode());
}
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
checkPlayServices();
}
@Override
protected void onStart() {
super.onStart();
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
Log.i(TAG, "mGoogleApiClient.connect()");
}
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
MyJobService class
public class MyJobService extends JobService {
@Override
public boolean onStartJob(JobParameters jobParameters) {
latitude = jobParameters.getExtras().getString("lat");
longitude = jobParameters.getExtras().getString("lon");
Log.e("service1",latitude + "");
Log.e("service2",longitude + "");
return true;
}
}
Update 1:
tried to implement the fused location in Jobservice but doesnot work
public class MyJobService extends JobService implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener{
String latitude = null;
String longitude = null;
public MyJobService() {
}
@Override
public boolean onStartJob(JobParameters jobParameters) {
Log.d("onStart", "onStartJob() :: ");
return false;
}
@Override
public boolean onStopJob(JobParameters jobParameters) {
Toast.makeText(this,
"MyJobService.onStopJob()",
Toast.LENGTH_SHORT).show();
return false;
}
//fused location provider starts
private GoogleApiClient mGoogleApiClient;
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 1000;
private LocationRequest mLocationRequest;
private static final String TAG = "zzzz";
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
private boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
// GooglePlayServicesUtil.getErrorDialog(resultCode, this,
// PLAY_SERVICES_RESOLUTION_REQUEST).show();
Log.e("GooglePlayServices", resultCode + "");
} else {
Toast.makeText(getApplicationContext(),
"This device is not supported.", Toast.LENGTH_LONG)
.show();
stopSelf();
}
return false;
}
return true;
}
@Override
public void onConnected(Bundle bundle) {
createLocationRequest(bundle);
}
protected void createLocationRequest(Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, new LocationCallback() {
@Override
public void onLocationResult(final LocationResult locationResult) {
latitude = locationResult.getLastLocation().getLatitude() + "";
longitude = locationResult.getLastLocation().getLongitude() + "";
Log.e("onLocationResult lat", latitude);
Log.e("onLocationResult Lon", longitude);
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
}
}, null);
}
@Override
public void onConnectionSuspended(int i) {
mGoogleApiClient.connect();
}
@Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = "
+ result.getErrorCode());
}
// fused location provider ends
}
Upvotes: 3
Views: 5080
Reputation: 121
Building on the updates and previous answers, I was finally able to get it working.
By calling fusedLocationProvider
to getLastKnownLocation
in the onStartJob of my job scheduler.
See the following code
ComponentName jobServiceComponent = new ComponentName(context, LocationJobService.class);
JobInfo.Builder jobInfoBuilder = new JobInfo.Builder(0, jobServiceComponent);
jobInfoBuilder.setPeriodic(Constants.JOB_SERVICE_INTERVAL);
jobInfoBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
jobInfoBuilder.setRequiresCharging(false);
jobInfoBuilder.setRequiresDeviceIdle(false);
jobInfoBuilder.setPersisted(true);
JobScheduler scheduler = (JobScheduler) context.getSystemService(JOB_SCHEDULER_SERVICE);
int resultCode = scheduler.schedule(jobInfoBuilder.build());
And to start this job scheduler
@Override
public boolean onStartJob(JobParameters params) {
updateBackgroundLocation(params);
return true;
}
private void updateBackgroundLocation(JobParameters params) {
if (jobCancelled) { return; }
new Thread(new Runnable() {
@Override
public void run() {
updateLocation(params);
}
}).start();
}
private void updateLocation(JobParameters params) {
LocationServices.getFusedLocationProviderClient(getApplicationContext())
.getLastLocation().addOnSuccessListener(location -> {
//perform your update here with last known location.
}).addOnFailureListener(e -> {
e.printStackTrace();
});
jobFinished(params, true);
}
@Override
public boolean onStopJob(JobParameters params) {
jobCancelled = true;
return false;
}
Upvotes: 1
Reputation: 31
I don't know if you are still trying to solve this issue, but the problem is the job scheduler always gets the wrong data when the app is destroyed (old data). The solution might be to buffer sqlite database on your phone. Because the database isn't wiped when destroying the app, you can put your newest GPS data into the database and then let the scheduler take it from there. It should work just fine.
please be kind, its my first time trying to help ;)
Upvotes: 3
Reputation: 4705
You need to put your fused location service logic in Job service, Because when you close your app your location listener also destroyed, So you need to get new location in your job service when your app is not available in foreground or background, When your job service called your decided time you need to implement logic of getting location, Also logic of update location,
You can get location by using last known location.
Upvotes: 2