0

I am trying to fetch location at certain intervals of time when the app is closed and to do so I tried using the GoogleApiClient's get last known location and to trigger that using a JobService. I have implemented the ConnectionCallbacks on the JobScheduler class. But the problem is that the onConnected() callback is never called.I think that the service is destroyed before any callback is returned. So what will be an efficient way to implement this logic.

My job service class

public class TestJobService extends JobService
{
protected GoogleApiClient mGoogleApiClient;
protected Location mLastLocation;
protected JobParameters mJobParameters;
public TestJobService() {
    super();
}
private class GetLocation extends AsyncTask<Integer, Void, Integer> implements GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener {
    protected Integer doInBackground(Integer... jobID) {
        if (mGoogleApiClient == null) {
            mGoogleApiClient = new GoogleApiClient.Builder(getBaseContext())
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .addApi(LocationServices.API)
                    .build();
        }

        return jobID[0];
    }



    protected void onPostExecute(Integer jobID) {
        Log.i("JobSchedulerTest","Job Finished!");
        jobFinished(mJobParameters, true);
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        mLastLocation=LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
        Log.i("JobSchedulerTest", "on start job: " + mJobParameters.getJobId() + "," +
                DateFormat.getTimeInstance().format(new Date())+
                ",Location("+mLastLocation.getLatitude()+","+mLastLocation.getLongitude()+")");

    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

    }
}


@Override
public boolean onStartJob(JobParameters jobParameters) {
    Log.i("JobSchedulerTest","Job Running!");
    mJobParameters=jobParameters;
    Integer i=new Integer(mJobParameters.getJobId());
    new GetLocation().execute(i);
    return true;

}

@Override
public boolean onStopJob(JobParameters jobParameters) {
    Log.i("JobSchedulerTest","Job Stopped!");
    return true;
}

}

I have called the job in an activity giving these parameters

 private void scheduleJob() {
        ComponentName mServiceComponent = new ComponentName(this, TestJobService.class);
        JobInfo.Builder builder = new JobInfo.Builder(5,mServiceComponent);
        //builder.setMinimumLatency(5 * 1000); // wait at least
        //builder.setOverrideDeadline(50 * 1000); // maximum delay
        builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);// require unmetered network
        builder.setBackoffCriteria(5000,JobInfo.BACKOFF_POLICY_LINEAR);
        builder.setRequiresDeviceIdle(false); // we dont care if device should be idle
        builder.setRequiresCharging(false);// we don't care if the device is charging or not
        //builder.setPersisted(true);
        builder.setPeriodic(50*1000);

        JobScheduler jobScheduler = (JobScheduler)getApplication().getSystemService(Context.JOB_SCHEDULER_SERVICE);
        jobScheduler.schedule(builder.build());
    }

Logs about the job:

04-16 00:48:35.266 10455-10455/com.google.android.gms.location.sample.basiclocationsample I/JobSchedulerTest: Job Running!
04-16 00:48:35.293 10455-10455/com.google.android.gms.location.sample.basiclocationsample I/JobSchedulerTest: Job Finished!
04-16 00:48:37.484 2028-2951/? V/AlarmManager: sending alarm {c169dc type 3 *alarm*:android.content.jobscheduler.JOB_DELAY_EXPIRED}
04-16 00:48:37.550 2028-2028/? V/AlarmManager: done {c169dc, *alarm*:android.content.jobscheduler.JOB_DELAY_EXPIRED} [67ms]
04-16 00:48:37.555 10455-10455/com.google.android.gms.location.sample.basiclocationsample I/JobSchedulerTest: Job Running!
04-16 00:48:37.563 10455-10455/com.google.android.gms.location.sample.basiclocationsample I/JobSchedulerTest: Job Finished!
04-16 00:48:39.927 2028-2951/? V/AlarmManager: sending alarm {c169dc type 3 *alarm*:android.content.jobscheduler.JOB_DELAY_EXPIRED}
04-16 00:48:39.947 2028-2028/? V/AlarmManager: done {c169dc, *alarm*:android.content.jobscheduler.JOB_DELAY_EXPIRED} [23ms]
04-16 00:48:39.952 10455-10455/com.google.android.gms.location.sample.basiclocationsample I/JobSchedulerTest: Job Running!
04-16 00:48:39.957 10455-10455/com.google.android.gms.location.sample.basiclocationsample I/JobSchedulerTest: Job Finished!
04-16 00:48:50.078 2028-2951/? V/AlarmManager: sending alarm {c169dc type 3 *alarm*:android.content.jobscheduler.JOB_DELAY_EXPIRED}
04-16 00:48:50.114 2028-2028/? V/AlarmManager: done {c169dc, *alarm*:android.content.jobscheduler.JOB_DELAY_EXPIRED} [154ms]
04-16 00:48:50.117 10455-10455/com.google.android.gms.location.sample.basiclocationsample I/JobSchedulerTest: Job Running!
04-16 00:48:50.120 10455-10455/com.google.android.gms.location.sample.basiclocationsample I/JobSchedulerTest: Job Finished!

My onConnected implementation is never fired.

theSereneRebel
  • 196
  • 3
  • 16
  • Your `AsyncTask` is defunct as soon as `doInBackground()` returns, and your job is terminated microseconds later via `jobFinished()`. At that point, your whole process might get torn down. IMHO, `AsyncTask` is the wrong solution here (just use a `Thread`), and you cannot finish the job until you get your location (or after some timeout of your choosing, in case you will never get a location). – CommonsWare Apr 15 '17 at 19:40
  • I have no idea who "they" are. – CommonsWare Apr 15 '17 at 19:50
  • @CommonsWare can you please show the implementation using Threads, i am confused. – theSereneRebel Apr 15 '17 at 20:05

1 Answers1

1

You have to ask for location permission both in manifest and code to make it work.

Manifest

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

MainActivity class:

oncreate():

   private static final int MY_PERMISSIONS_REQUEST_FINE_LOCATION = 111;

   if (ContextCompat.checkSelfPermission(MainActivity.this,    // Check for permission
            android.Manifest.permission.ACCESS_FINE_LOCATION)
            != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(
                this, // Activity
                new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
                MY_PERMISSIONS_REQUEST_FINE_LOCATION);
    }
beck
  • 2,967
  • 3
  • 16
  • 27