Beim ersten Start funktioniert alles richtig, wenn Sie ein zweites Mal starten, wird dieser Fehler angezeigt
FATAL EXCEPTION: main
Process: ro.vrt.videoplayerstreaming, PID: 23662
Java.lang.IllegalStateException: Already managing a GoogleApiClient with id 0
at com.google.Android.gms.common.internal.zzx.zza(Unknown Source)
at com.google.Android.gms.common.api.internal.zzw.zza(Unknown Source)
at com.google.Android.gms.common.api.GoogleApiClient$Builder.zza(Unknown Source)
at com.google.Android.gms.common.api.GoogleApiClient$Builder.zze(Unknown Source)
at com.google.Android.gms.common.api.GoogleApiClient$Builder.build(Unknown Source)
at ro.vrt.videoplayerstreaming.Login.onCreateView(Login.Java:75)
at Android.support.v4.app.Fragment.performCreateView(Fragment.Java:1974)
at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:1067)
at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:1252)
at Android.support.v4.app.BackStackRecord.run(BackStackRecord.Java:738)
at Android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.Java:1617)
at Android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.Java:517)
at Android.os.Handler.handleCallback(Handler.Java:739)
at Android.os.Handler.dispatchMessage(Handler.Java:95)
at Android.os.Looper.loop(Looper.Java:148)
at Android.app.ActivityThread.main(ActivityThread.Java:5849)
at Java.lang.reflect.Method.invoke(Native Method)
at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:763)
at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:653)
Hier ist mein Code:
public class Login extends Fragment implements
GoogleApiClient.OnConnectionFailedListener,
View.OnClickListener {
private static final String TAG = "SignInActivity";
private static final int RC_SIGN_IN = 9001;
private GoogleApiClient mGoogleApiClient;
private TextView mStatusTextView;
private ProgressDialog mProgressDialog;
private static String url;
private static View view;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (view != null) {
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null)
parent.removeView(view);
}
try {
view = inflater.inflate(R.layout.activity_login, container, false);
// Views
mStatusTextView = (TextView) view.findViewById(R.id.status);
// Button listeners
view.findViewById(R.id.sign_in_button).setOnClickListener(this);
view.findViewById(R.id.sign_out_button).setOnClickListener(this);
view.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.
GoogleSignInOptions 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(getActivity())
.enableAutoManage(getActivity()/* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
// [END build_client]
// [START customize_button]
// Customize sign-in button. The sign-in button can be displayed in
// multiple sizes and color schemes. It can also be contextually
// rendered based on the requested scopes. For example. a red button may
// be displayed when Google+ scopes are requested, but a white button
// may be displayed when only basic profile is requested. Try adding the
// Scopes.PLUS_LOGIN scope to the GoogleSignInOptions to see the
// difference.
SignInButton signInButton = (SignInButton) view.findViewById(R.id.sign_in_button);
signInButton.setSize(SignInButton.SIZE_STANDARD);
signInButton.setScopes(gso.getScopeArray());
// [END customize_button]
} catch (InflateException e) {
/* map is already there, just return view as it is */
}
super.onCreate(savedInstanceState);
return view;
}
@Override
public void 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) {
//adaugat de mine sa porneacsa singur cererea de logare
signIn();
//fin
hideProgressDialog();
handleSignInResult(googleSignInResult);
}
});
}
}
// [START onActivityResult]
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
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);
}
}
// [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() + " Your token " + acct.getId()));
url = "http://grupovrt.ddns.net:81/index.php?token="+acct.getId();
updateUI(true);
} else {
// Signed out, show unauthenticated UI.
updateUI(false);
}
}
// [END handleSignInResult]
// [START signIn]
private void signIn() {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
}
// [END signIn]
// [START signOut]
private void signOut() {
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
// [START_EXCLUDE]
updateUI(false);
// [END_EXCLUDE]
}
});
}
// [END signOut]
// [START revokeAccess]
private void revokeAccess() {
Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
// [START_EXCLUDE]
updateUI(false);
// [END_EXCLUDE]
}
});
}
// [END revokeAccess]
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// An unresolvable error has occurred and Google APIs (including Sign-In) will not
// be available.
Log.d(TAG, "onConnectionFailed:" + connectionResult);
}
private void showProgressDialog() {
if (mProgressDialog == null) {
mProgressDialog = new ProgressDialog(getActivity());
mProgressDialog.setMessage(getString(R.string.loading));
mProgressDialog.setIndeterminate(true);
}
mProgressDialog.show();
}
private void hideProgressDialog() {
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.hide();
}
}
private void updateUI(boolean signedIn) {
if (signedIn) {
getView().findViewById(R.id.sign_in_button).setVisibility(View.GONE);
getView().findViewById(R.id.sign_out_and_disconnect).setVisibility(View.VISIBLE);
} else {
mStatusTextView.setText(R.string.signed_out);
getView().findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
getView().findViewById(R.id.sign_out_and_disconnect).setVisibility(View.GONE);
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.sign_in_button:
signIn();
break;
case R.id.sign_out_button:
signOut();
break;
case R.id.disconnect_button:
revokeAccess();
break;
}
}
}
Nach meinem Verständnis liegt das Problem in diesen Zeilen:
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.enableAutoManage(getActivity()/* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
Ich habe versucht, explizit eine ID von 0
zu übergeben:
.enableAutoManage(getActivity() /* FragmentActivity */, 0, this /* OnConnectionFailedListener */)
aber das hat immer noch nicht funktioniert.
Was vermisse ich?
Sie sollten stopAutoManage()
in der onPause()
-Methode Ihrer Fragment
aufrufen:
@Override
public void onPause() {
super.onPause();
mGoogleClient.stopAutoManage(getActivity());
mGoogleClient.disconnect();
}
Sie sollten stopAutoManage()
in der onPause()
-Methode Ihrer Fragment
aufrufen:
@Override
public void onPause() {
super.onPause();
mGoogleApiClient.stopAutoManage(getActivity());
mGoogleApiClient.disconnect();
}
Um weitere Probleme zu vermeiden
@Override
public void onStop() {
super.onStop();
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
mGoogleApiClient.stopAutoManage((Activity) context);
mGoogleApiClient.disconnect();
}
}
Ich hatte ein ähnliches Problem, als ich einen Login-Button in zwei verschiedenen Fragment
s platzierte, die zu derselben Activity
gehörten.
Ich habe dieses Problem gelöst, indem ich jeder automatisch verwalteten GoogleApiClient
unterschiedliche IDs zuweist.
Zum Beispiel in Fragment
1 beim Erstellen meines GoogleApiClient
-Objekts, dem ich 0 als ID zugewiesen habe:
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.enableAutoManage(getActivity(), 0, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
In Fragment
2, während ich mein GoogleApiClient
-Objekt erstellte, dem ich 1 als ID zugewiesen habe:
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.enableAutoManage(getActivity(), 1, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
Das offizielle Dokument für enableAutoManage sagt folgendes:
Zu jeder Zeit ist nur ein automatisch verwalteter Client pro ID zulässig. Um eine ID wiederzuverwenden, müssen Sie zunächst stopAutoManage (FragmentActivity) auf dem vorherigen Client aufrufen.
In Ihrem Code wird die Version von enableAutoManage ohne Parameter clientId verwendet. Der Standardwert ist 0. Nachstehend werde ich Ihnen erklären, warum Sie mehrere automatisch verwaltete Clients für clientId 0 verwenden. Vor dieser Warnung wird in der obigen Dokumentation gewarnt.
Nachdem Ihr Anmeldungsfragment an eine FragmentActivity angefügt wurde, weist es diese Aktivität an, mit der Verwaltung einer neuen Instanz von GoogleApiClient zu beginnen. Was aber, wenn FragmentActivity bereits eine andere Instanz von GoogleApiClient verwaltet? Dann bekommst du den Fehler.
Es gibt einige mögliche Szenarien, die zu dieser Situation mit mehreren GoogleApiClients-per-FragmentActivity führen können.
Vielleicht fügen Sie in einer FragmentTransaction das Anmeldefragment hinzu und rufen AddToBackStack auf. Dann tippt der Benutzer zurück, und später wird das Anmeldefragment irgendwie erneut angefügt. In diesem Fall lauten die wichtigsten Aufrufe der Login-Aktivitätsmethode onCreateView -> onDestroyView -> onCreateView:
Dies ist problematisch, da der zweite Aufruf von Login.onCreateView versucht, FragmentActivity einen zweiten GoogleApiClient verwalten zu lassen.
Wenn ich Sie wäre, würde ich ernsthaft in Betracht ziehen, den GoogleApiClient in der Aktivität zu erstellen, anstatt in Fragmenten. Dann können Sie entweder die Arbeit ausführen, für die der GoogleApiClient in der Aktivität erforderlich ist, oder Sie können dies im Anmelde-Fragment fortsetzen, nachdem Sie den GoogleApiClient aus der Aktivität abgerufen haben.
private GoogleApiClient googleApiClient;
@Override
void onAttach(Activity activity) {
super.onAttach(activity);
googleApiClient = activity.getGoogleApiClient();
}
@Override
void onDetach() {
super.onDetach();
googleApiClient = null;
}
Ich schlage vor, dass Sie Ihre mGoogleApiClient
in onCreate()
statt in onCreateView()
initialisieren.
Wie auf @vlazzle hinweist, kann onCreateView()
während der Lebensdauer einer einzelnen Activity
mehr als einmal aufgerufen werden.
Sie sollten stopAutoManage()
in der onDestroy()
-Methode Ihres Fragments wie folgt aufrufen:
@Override
public void onDestroy() {
super.onDestroy();
mGoogleApiClient.stopAutoManage(getActivity());
mGoogleApiClient.disconnect();
}