Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LocationClient not connected in "onConnected" method

Has someone already had this problem: - I'm initializing a LocationClient, with ConnectionCallbacks and so on... - Then, I call "connect()" on it. - In my "onConnected" method, I call myLocationClient.getLastLocation(), which makes the app crash on some people devices, with exception :

"Fatal Exception: java.lang.IllegalStateException Not connected. Call connect() and wait for onConnected() to be called."

Any idea?

Here's some part of the code:

myLocationClient = new LocationClient(this, new ConnectionCallbacks() {
        @Override
        public void onDisconnected() {
        //Do some stuff here
        }

        @Override
        public void onConnected(Bundle arg0) {
            if(myLocationClient.getLastLocation() != null) {
                //Do some other stuff here
            }
        }
    }, new OnConnectionFailedListener() {
        @Override
        public void onConnectionFailed(ConnectionResult arg0) {
        //Do other stuff here
        }
});

myLocationClient.connect();

The app crashes on the first line of the "onConnected" method.

For people who want the stack here it is:

java.lang.IllegalStateException: Not connected. Call connect() and wait for onConnected() to be called.
at com.google.android.gms.internal.k.B()
at com.google.android.gms.internal.bh.a()
at com.google.android.gms.internal.bh$c.B()
at com.google.android.gms.internal.bg.getLastLocation()
at com.google.android.gms.internal.bh.getLastLocation()
at com.google.android.gms.location.LocationClient.getLastLocation()
at com.myAppPackage.onConnected(AroundMeActivity.java:321)
at com.google.android.gms.internal.k.y()
at com.google.android.gms.internal.k$f.a()
at com.google.android.gms.internal.k$f.a()
at com.google.android.gms.internal.k$b.D()
at com.google.android.gms.internal.k$a.handleMessage()
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5419)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025)
at dalvik.system.NativeStart.main(NativeStart.java)
like image 385
Jeje Doudou Avatar asked Mar 19 '23 22:03

Jeje Doudou


1 Answers

The locationClient.getLastLocation() gets the last known location from the client. However, the Fused Location Provider will only maintain background location if at least one client is connected to it. Once the first client connects, it will immediately try to get a location. If your activity is the first client to connect and you call getLastLocation() right away in onConnected(), that might not be enough time for the first location to come in. This will result in location being null.

To solve this issue, you have to wait (indeterminately) till the provider gets the location and then call getLastLocation(), which is impossible to know.
Another (better) option is to implement the com.google.android.gms.location.LocationListener interface to receive periodic location updates (and switch it off once you get the first update).

public class MyActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener {
// . . . . . . . . more stuff here 
LocationRequest locationRequest;
LocationClient locationClient;

@Override
protected void onCreate(Bundle savedInstanceState) {
    // . . . . other initialization code
    locationClient = new LocationClient(this, this, this);
    locationRequest = new LocationRequest();
    // Use high accuracy
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    // Set the update interval to 5 seconds
    locationRequest.setInterval(UPDATE_INTERVAL);
    // Set the fastest update interval to 1 second
    locationRequest.setFastestInterval(FASTEST_INTERVAL);
}
// . . . . . . . . other methods 
@Override
public void onConnected(Bundle bundle) {
    Location location = locationClient.getLastLocation();
    if (location == null)
        locationClient.requestLocationUpdates(locationRequest, this);
    else
        Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show();
}
// . . . . . . . . other methods
@Override
public void onLocationChanged(Location location) {
    locationClient.removeLocationUpdates(this);
    // Use the location here!!!
}

In this code, you’re checking if the client already has the last location (in onConnected). If not, you’re requesting for location updates, and switching off the requests (in onLocationChanged() callback) as soon as you get an update.

UPDATE:

Many times, the user would have location services disabled (to save battery, or privacy reasons). In such a case, the code above will still request for location updates, but onLocationChanged will never get called. You can stop the requests by checking if the user has disabled the location services.

If your app requires them to enable location services, you would want to show a message or a toast. Unfortunately, there is no way of checking if the user has disabled location services in Google’s Location Services API. For this, you will have to resort back to Android’s API.

In your onCreate method:

LocationManager manager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER) && !manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
    locationEnabled = false;
    Toast.makeText(getActivity(), "Enable location services for accurate data",     Toast.LENGTH_SHORT).show();
}
else locationEnabled = true;

And use the locationEnabled flag in your onConnected method like this:

if (location != null) {
Toast.makeText(getActivity(), "Location: " + location.getLatitude() + ", " + location.getLongitude(), Toast.LENGTH_SHORT).show();
}
else if (location == null && locationEnabled) {
    locationClient.requestLocationUpdates(locationRequest, this);
}

Special thanks to Rahul Jiresal.

like image 157
Dr.jacky Avatar answered Apr 05 '23 23:04

Dr.jacky