Erreur dans le Fragment: “Déjà de gestion de GoogleApiClient avec l'id 0”
Tout fonctionne dès la première fois, si vous lancez un deuxième temps vous voyez ce message d'erreur:
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)
Voici mon 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;
}
}
}
Ce que je comprends, le problème est dans ces lignes:
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.enableAutoManage(getActivity()/* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
J'ai essayé explicitement passage d'un id de 0
:
.enableAutoManage(getActivity() /* FragmentActivity */, 0, this /* OnConnectionFailedListener */)
mais cela ne fonctionne toujours pas.
Ce qui me manque?
Vous devez vous connecter pour publier un commentaire.
Vous devriez appeler
stopAutoManage()
dans leonPause()
méthode de votreFragment
:revokeAccess
. (Y)stopAutoManage()
etrevokeAccess
?if (mGoogleClient!= null && mGoogleClient.isConnected())
Vous devriez appeler
stopAutoManage()
dans leonPause()
méthode de votreFragment
comme suit:GoogleApiClient.Builder
deonActivityCreated()
méthode du fragment. Et quand je goto certains autres de l'écran,onPause
est appelée et leapiclient
est déconnecté. Et quand je l'ai reprise, estonActivityCreated
appelé?Pour éviter un autre problème
J'ai fait face à un problème similaire quand j'ai placé un bouton de connexion en deux
Fragment
s appartenant à la mêmeActivity
.J'ai résolu ce problème par l'affectation de différents identifiants à chaque automatiquement géré
GoogleApiClient
.Par exemple, dans
Fragment
1, lors de la création de monGoogleApiClient
objet que je attribué 0 comme id:Dans
Fragment
2, lors de la création de monGoogleApiClient
objet que je attribué 1 comme id:La officiel doc pour enableAutoManage dit ceci:
Votre code à l'aide de la version de enableAutoManage sans clientId paramètre, donc il est à 0 par défaut. Ci-dessous je vais expliquer pourquoi vous avez plusieurs auto-géré de clients pour clientId 0, qui est ce que la documentation ci-dessus est mise en garde contre.
Après votre identifiant de Fragment est attaché à un FragmentActivity, il indique que l'activité de commencer la gestion d'une nouvelle instance de GoogleApiClient. Mais que faire si le FragmentActivity est déjà la gestion d'une autre instance de GoogleApiClient? C'est quand vous obtenez l'erreur.
Il y a quelques scénarios possibles qui peuvent conduire jusqu'à cette de plusieurs GoogleApiClients par FragmentActivity situation.
Peut-être que vous ajoutez de Connexion Fragment dans un FragmentTransaction et que vous appelez addToBackStack. Ensuite, l'utilisateur appuie sur le dos, puis, plus tard, d'une certaine manière l'identifiant de Fragment est de nouveau attaché. Dans ce cas, l'importance de l'Activité de Connexion des appels de méthode sont onCreateView -> onDestroyView -> onCreateView comme indiqué ici:
C'est problématique parce que le second appel à la Connexion.onCreateView essaie d'avoir FragmentActivity gérer une deuxième GoogleApiClient.
Si j'étais vous, je serais sérieusement envisager de créer la GoogleApiClient dans l'activité plutôt que dans les fragments. Ensuite, vous pouvez soit faire le travail que nécessite GoogleApiClient dans l'Activité, ou de continuer à le faire dans la Connexion Fragment après l'obtention de la GoogleApiClient de l'Activité comme suit:
Je suggère que vous initialisez votre
mGoogleApiClient
dansonCreate()
au lieu deonCreateView()
.Comme signalé par @vlazzle,
onCreateView()
peut être appelé plus d'une fois au cours d'une seuleActivity
's la durée de vie.Vous devriez appeler
stopAutoManage()
dans leonDestroy()
méthode de votre fragment de la sorte:L'objet d'une réponse ne fonctionnera pas si vous utilisez
Login
fragment dans une Activité à plusieurs reprises, car l'ajout du fragment de façon séquentielle dans un court laps de temps conduira le même incident. Android parfois des mélanges de cycle de vie de Fragments ajoutés à une Activité.Donc je vous conseille de faire
mGoogleApiClient
personnel dans un résumé séparé de l'Activité, et de faire toutes les activités de l'ajout deLogin
fragment de prolonger cette Activité.J'ai réussi à me débarrasser de ce problème par la création de ce résumé de l'Activité ci-dessous, il suffit de copier coller dans votre projet:
Après que vous avez déplacé
googleApiClient
àLoginableActivity
vous pouvez accéder àgoogleApiClient
deLogin
fragment comme ceci (nous allons le faire avec Java):Essayez d'utiliser votre
mGoogleApiClient
de votre activité.si vous avez déclaré
GoogleApiClient
sur votre activité, alors vous ne pouvez pas re-déclarée sur votre fragment. au lieu de cela, la ré-utilisation de variable dans l'activité de fragmentremplacer
YouractivityClass
avec votre activité de votre fragment, et assurez-vous de fixer votremGoogleApiClient
champ de votre activité publique