I want to collect location updates for a specific time duration and do something with the locations at the end. I currently keep track of the time passed in the method onLocationChanged.
public class LocationProvider implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private static final String TAG = LocationProvider.class.getSimpleName();
private Context mContext;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private long mStartTime;
private long mDuration;
List<Location> locations;
public LocationProvider(Context context) {
mContext = context;
GoogleApiAvailability api = GoogleApiAvailability.getInstance();
if (api.isGooglePlayServicesAvailable(mContext) == ConnectionResult.SUCCESS) {
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
} else {
Log.e(TAG, "Could not connect to Google Play services");
}
}
@Override
public void onConnected(Bundle bundle) {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.e(TAG, "onConnectionFailed: " + connectionResult.toString());
}
@Override
public void onConnectionSuspended(int i) {
Log.e(TAG, "GoogleApiClient connection has been suspended: " + String.valueOf(i));
}
@Override
public void onLocationChanged(Location location) {
locations.add(location);
if (System.currentTimeMillis() - mStartTime > mDuration) {
stopTracking();
// do stuff
}
}
public void startTracking(long interval, long fastInterval, long duration) {
mDuration = duration;
locations = new ArrayList<>();
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(interval)
.setFastestInterval(fastInterval);
if (!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting()) {
mGoogleApiClient.connect();
}
mStartTime = System.currentTimeMillis();
}
private void stopTracking() {
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
}
}
However, I want to divorce this logic, because I want to do different things with the locations depending on my needs. I reasoned that if I created a new thread for registering my location listener, I could wait on the main thread until the location collection completed to use the locations list.
public class LocationUpdates {
private LocationProvider mLocationProvider;
private Looper mLooper;
public List<Location> gatherUpdates(final Context context,
final long interval,
final long fastInterval,
final long duration)
throws InterruptedException {
long startTime = System.currentTimeMillis();
new Thread() {
@Override
public void run() {
Looper.prepare();
mLooper = Looper.myLooper();
mLocationProvider = new LocationProvider(context);
mLocationProvider.startTracking(interval, fastInterval, duration);
Looper.loop();
}
}.start();
while (System.currentTimeMillis() - startTime < duration) {
}
mLooper.quit();
mLooper.getThread().join();
return mLocationProvider.locations;
}
}
Instead, what I observed was (interval 3 seconds, duration 10 seconds):
- the line
mLocationProvider.startTracking(interval, fastInterval, duration);is reached gatherUpdatesreturns after however longonLocationChangedis called for the first time only now
So, even though the location listener is registered, something clearly blocks it from receiving updates. I can't figure out why my logic doesn't do what I expect it to do.
Is there a way, even without a thread, to collect a bunch of location updates and work with them outside of onLocationChanged only after the collection has finished?
You could build your Location Updates request with an
Intentto aBroadcastReceiver. Then remove the updates when the location object's time exceeds your duration.In your broadcast receiver: