Google API client bug, sending locations

2019-07-21 06:28发布

问题:

I want to create that I send every few seconds a message to GCM. But after some time I want to remove the locationupdates again. For sending the data to the intentservice of gcm I use a pendingintent. Now every time and it happens a lot I get this error :

Caused by:

java.lang.IllegalStateException: GoogleApiClient is not connected yet.
            at com.google.android.gms.common.internal.n.a(Unknown Source)
            at com.google.android.gms.common.api.b.b(Unknown Source)
            at com.google.android.gms.internal.lt.removeLocationUpdates(Unknown Source)
            at com.example.task_1.Location.LocationUpdate.stopLocationUpdates(LocationUpdate.java:83)
            at com.example.task_1.Location.LocationUpdate.onStartCommand(LocationUpdate.java:52)
            at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2704)
            at android.app.ActivityThread.access$1900(ActivityThread.java:141)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1353)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5103)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
            at dalvik.system.NativeStart.main(Native Method)

This is my code:

public class LocationUpdate extends Service implements GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {
    private static final String TAG = "DRIVER";
    private SharedPreferences pref;
    private String driverId;
    private GoogleApiClient mGoogleApiClient;
    private LocationRequest mLocationRequest;
    private Intent mGcmIntentService;
    private PendingIntent mPendingIntent;

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand");
        super.onStartCommand(intent, flags, startId);
        boolean stopService = false;
        if (intent != null)
            stopService = intent.getBooleanExtra("stopservice", false);
        if (stopService)
            stopLocationUpdates();
        return START_STICKY;
    }

    @Override
    public void onCreate() {
        Log.e(TAG, "onCreate");
        pref = getSharedPreferences("driver_app", MODE_PRIVATE);
        driverId = pref.getString("driver_id", "");
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(LocationServices.API).addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this).build();
        mGoogleApiClient.connect();
    }

    @Override
    public void onDestroy() {
        Log.e(TAG, "onDestroy");
        super.onDestroy();

    }

    public void stopLocationUpdates() {
        if(!mGoogleApiClient.isConnected()){
            mGoogleApiClient.connect();
        }
        mGcmIntentService = new Intent(this,SendDataIntentService.class);
        mGcmIntentService.putExtra("ID", "FusedLocation");
        mPendingIntent = PendingIntent.getService(this, 0, mGcmIntentService, PendingIntent.FLAG_CANCEL_CURRENT);
        LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, mPendingIntent);
        if (mGoogleApiClient.isConnected())
            mGoogleApiClient.disconnect();
    }
    @Override
    public void onConnectionFailed(ConnectionResult arg0) {
        // TODO Auto-generated method stub
    }

    @Override
    public void onConnected(Bundle arg0) {
        // TODO Auto-generated method stub
        mLocationRequest = LocationRequest.create();
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        mLocationRequest.setInterval(30000);
        startLocationUpdates();
    }
    private void startLocationUpdates() {
        mGcmIntentService = new Intent(this,SendDataIntentService.class);
        mGcmIntentService.putExtra("ID", "FusedLocation");
        mPendingIntent = PendingIntent.getService(this, 0, mGcmIntentService, PendingIntent.FLAG_CANCEL_CURRENT);
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mPendingIntent);
    }

    @Override
    public void onConnectionSuspended(int arg0) {
        // TODO Auto-generated method stub

    }

}

Anyone know how to solve this bug? Or how to fix it? I searched on the internet but can't find anything.

回答1:

The problem is that in your stopLocationUpdates() method, you are not waiting for the API to be connected before you call removeLocationUpdates().

One simple way to fix this would be to set a boolean flag when you need to remove location callbacks, but the API is not connected.

Add a member variable:

private boolean isRemoving = false;

Then modify the logic so that it waits for the API to connect before unregistering for location callbacks.

In the stopLocationUpdates() method:

public void stopLocationUpdates() {
    if(!mGoogleApiClient.isConnected()){
        isRemoving = true; //added
        mGoogleApiClient.connect();
    }
    else {
        mGcmIntentService = new Intent(this, SendDataIntentService.class);
        mGcmIntentService.putExtra("ID", "FusedLocation");
        mPendingIntent = PendingIntent.getService(this, 0, mGcmIntentService, PendingIntent.FLAG_CANCEL_CURRENT);
        LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, mPendingIntent);
        if (mGoogleApiClient.isConnected())
            mGoogleApiClient.disconnect();
    }
}

In the onConnected() callback:

@Override
public void onConnected(Bundle arg0) {

    if (isRemoving){
        stopLocationUpdates();
    }
    else {
        // TODO Auto-generated method stub
        mLocationRequest = LocationRequest.create();
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        mLocationRequest.setInterval(30000);
        startLocationUpdates();
    }
}

You would also want to set the flag back to false in startLocationUpdates():

private void startLocationUpdates() {
    isRemoving = false; //added
    mGcmIntentService = new Intent(this,SendDataIntentService.class);
    mGcmIntentService.putExtra("ID", "FusedLocation");
    mPendingIntent = PendingIntent.getService(this, 0, mGcmIntentService, PendingIntent.FLAG_CANCEL_CURRENT);
    LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mPendingIntent);
}

Also in onCreate():

@Override
public void onCreate() {
    Log.e(TAG, "onCreate");
    isRemoving = false; //added
    pref = getSharedPreferences("driver_app", MODE_PRIVATE);
    driverId = pref.getString("driver_id", "");
    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addApi(LocationServices.API).addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this).build();
    mGoogleApiClient.connect();
}

Edit: To re-start the location callbacks after they have been previously cancelled, you can use the onStartCommand() method.

Modify onStartCommand() so that it can both stop and start location updates:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.e(TAG, "onStartCommand");
    super.onStartCommand(intent, flags, startId);
    boolean stopService = false;
    if (intent != null) {
        stopService = intent.getBooleanExtra("stopservice", false);
    }

    if (stopService) {
        stopLocationUpdates();
    }
    else{
        isRemoving = false;
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(LocationServices.API).addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this).build();
        mGoogleApiClient.connect();
    }
    return START_STICKY;
}

Then, in order to re-start location updates, you would call startService() with an Intent that has stopservice set to false:

    Intent i = new Intent(this, LocationUpdate.class);
    i.putExtra("stopservice", false);
    startService(i);