Illegal state exception while calling signout thro

2019-07-18 09:57发布

问题:

I wanted to implement a Google signin activity which on success opens my next activity. If the user logs out from the next activity, I want to go back to Google signin activity and signout. However when I call signout in onActivityResult I get the following exception

Caused by: java.lang.IllegalStateException: GoogleApiClient is not connected yet.

Here's the relevant code

public class LoginActivity extends AppCompatActivity implements
    GoogleApiClient.OnConnectionFailedListener,
    View.OnClickListener {

private static final String TAG = "LoginActivity";
private static final int RC_SIGN_IN = 9001;

private GoogleApiClient mGoogleApiClient;
private GoogleSignInOptions gso;
private TextView mStatusTextView;
private ProgressDialog mProgressDialog;

@Override
protected void onCreate(Bundle savedInstanceState) {
    Log.d(TAG, "onCreate()");
    super.onCreate(savedInstanceState);
    setContentView(R.layout.signin_activity);

    // Views
    mStatusTextView = (TextView) findViewById(R.id.status);

    // Button listeners
    findViewById(R.id.sign_in_button).setOnClickListener(this);
    findViewById(R.id.sign_out_button).setOnClickListener(this);
    findViewById(R.id.disconnect_button).setOnClickListener(this);

    // [START configure_signin]
    // Configure sign-in to request the user's ID, email address, and basic
    // profile. ID and basic profile are included in DEFAULT_SIGN_IN.
    gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestEmail()
            .build();
    // [END configure_signin]

    // [START build_client]
    // Build a GoogleApiClient with access to the Google Sign-In API and the
    // options specified by gso.
    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
            .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
            .build();
    // [END build_client]

    SignInButton signInButton = (SignInButton) findViewById(R.id.sign_in_button);
    signInButton.setSize(SignInButton.SIZE_STANDARD);
    signInButton.setScopes(gso.getScopeArray());
    // [END customize_button]
}

@Override
public void onStart() {
    Log.d(TAG, "onStart()");
    super.onStart();
    OptionalPendingResult<GoogleSignInResult> opr = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient);
        if (opr.isDone()) {
            // If the user's cached credentials are valid, the OptionalPendingResult will be "done"

            // and the GoogleSignInResult will be available instantly.
            Log.d(TAG, "Got cached sign-in");
            GoogleSignInResult result = opr.get();
            handleSignInResult(result);
        } else {
            // If the user has not previously signed in on this device or the sign-in has
            // expired,
            // this asynchronous branch will attempt to sign in the user silently.  Cross-device
            // single sign-on will occur in this branch.
            showProgressDialog();
            opr.setResultCallback(new ResultCallback<GoogleSignInResult>() {
                @Override
                public void onResult(GoogleSignInResult googleSignInResult) {
                    hideProgressDialog();
                    handleSignInResult(googleSignInResult);
                }
            });
        }
}

// [START onActivityResult]
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    Log.d(TAG, "onActivityResult()");
    super.onActivityResult(requestCode, resultCode, data);

    // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
    if (requestCode == RC_SIGN_IN) {
        GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
        handleSignInResult(result);
    }
    else if (requestCode == Constants.MAPS_ACTIVITY_FINISHED) {
        if (resultCode == Constants.SIGNOUT) {
            signOut();
        }
    }
}
// [END onActivityResult]


// [START handleSignInResult]
private void handleSignInResult(GoogleSignInResult result) {
    Log.d(TAG, "handleSignInResult:" + result.isSuccess());
    if (result.isSuccess()) {
        // Signed in successfully, show authenticated UI.
        GoogleSignInAccount acct = result.getSignInAccount();
        mStatusTextView.setText(getString(R.string.signed_in_fmt, acct.getDisplayName()));
        updateUI(true);
        Intent intent = new Intent(this, MapsActivity.class);
        startActivityForResult(intent, Constants.MAPS_ACTIVITY_FINISHED);
    } else {
        // Signed out, show unauthenticated UI.
        updateUI(false);
    }
}
// [END handleSignInResult]

// [START signIn]
private void signIn() {
    Log.d(TAG, "signin()");
    Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
    startActivityForResult(signInIntent, RC_SIGN_IN);
}
// [END signIn]

// [START signOut]
private void signOut() {
    Log.d(TAG, "signout()");
    Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
            new ResultCallback<Status>() {
                @Override
                public void onResult(Status status) {
                    // [START_EXCLUDE]
                    updateUI(false);
                    // [END_EXCLUDE]
                }
            });
}
// [END signOut]
}

回答1:

Your exception tells you what the problem is: your client is not connected. First of all I suggest that you check out this guide about Google API Client.

Anyway, what you should do is add the following code somewhere to your app:

mGoogleApiClient.connect();

This code will send a connection request, and if everything is fine, your client will get connected. After that, before you use it, you should check if the client is connected to avoid this error in future:

if (mGoogleApiClient.isConnected()) {
    // do your stuff with Google Api Client
}


回答2:

According to the Javadoc:

1) signOut:

public abstract PendingResult<Status> signOut (GoogleApiClient client)
Parameters
client  The connected GoogleApiClient to service the call.

2) getSignInIntent

public abstract Intent getSignInIntent (GoogleApiClient client)
Parameters
client  The GoogleApiClient to service the call.

signOut call requires a connected GoogleApiClient; while getSignInIntent() doesn't. In Google's sample, sign-out button is only enabled after signing-in, which can guarantee a connected GoogleApiClient. However, in your case, you will need to explicitly listen to onConnected before calling signOut. You can use GoogleApiClient.Builder.addConnectionCallbacks to register an onConnected listener, and making sure you queue the signOut request until onConnected is called back.

(Since you used autoManage, GoogleApiClient internal will auto-connect in onStart() and auto-disconnect in onStop)