通过 GoogleApiClient 调用注销时出现非法状态异常

Illegal state exception while calling signout through GoogleApiClient

我想实现一个 Google 登录 activity,成功后会打开我的下一个 activity。如果用户从下一个 activity 注销,我想返回 Google 登录 activity 并注销。但是,当我在 onActivityResult 中调用注销时,出现以下异常

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

这是相关代码

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]
}

您的异常告诉您问题所在:您的客户端未连接。首先,我建议您查看 this guide 关于 Google API 客户端。

无论如何,您应该将以下代码添加到您的应用中:

mGoogleApiClient.connect();

此代码将发送一个连接请求,如果一切正常,您的客户端将会连接。之后,在你使用它之前,你应该检查客户端是否已连接,以避免以后出现此错误:

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

根据 Javadoc:

1) 注销:

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 调用需要 已连接 GoogleApiClient;而 getSignInIntent() 没有。在 Google 的示例中,退出按钮仅在登录后启用,这可以保证连接的 GoogleApiClient。但是,在您的情况下,您需要在调用 signOut 之前明确监听 onConnected。您可以使用 GoogleApiClient.Builder.addConnectionCallbacks 注册一个 onConnected 侦听器,并确保将注销请求排队直到 onConnected 被回调。

(由于您使用了 autoManage,GoogleApiClient 内部将在 onStart() 中自动连接并在 onStop 中自动断开连接)