Tout fonctionne correctement la première fois, si vous lancez une deuxième fois, vous voyez cette 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;
}
}
}
Si je comprends bien, 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 de passer un identifiant de 0
:
.enableAutoManage(getActivity() /* FragmentActivity */, 0, this /* OnConnectionFailedListener */)
mais cela n'a toujours pas fonctionné.
Qu'est-ce que je rate?
Vous devez appeler stopAutoManage()
dans la méthode onPause()
de votre Fragment
:
@Override
public void onPause() {
super.onPause();
mGoogleClient.stopAutoManage(getActivity());
mGoogleClient.disconnect();
}
Vous devriez appeler stopAutoManage()
dans la méthode onPause()
de votre Fragment
comme ceci:
@Override
public void onPause() {
super.onPause();
mGoogleApiClient.stopAutoManage(getActivity());
mGoogleApiClient.disconnect();
}
Pour éviter d'autres problèmes
@Override
public void onStop() {
super.onStop();
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
mGoogleApiClient.stopAutoManage((Activity) context);
mGoogleApiClient.disconnect();
}
}
J'ai rencontré un problème similaire lorsque j'ai placé un bouton de connexion dans deux Fragment
s différents appartenant au même Activity
.
J'ai résolu ce problème en affectant différents identifiants à chaque GoogleApiClient
géré automatiquement.
Par exemple, dans Fragment
1, lors de la création de mon objet GoogleApiClient
, je ai assigné 0 en tant qu'id:
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.enableAutoManage(getActivity(), 0, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
Dans Fragment
2, lors de la création de mon objet GoogleApiClient
, je ai affecté 1 en tant qu'id:
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.enableAutoManage(getActivity(), 1, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
Le doc officiel de enableAutoManage dit ceci:
À tout moment, un seul client géré automatiquement est autorisé par identifiant. Pour réutiliser un identifiant, vous devez d'abord appeler stopAutoManage (FragmentActivity) sur le client précédent.
Votre code utilise la version de enableAutoManage sans paramètre clientId. Par conséquent, la valeur par défaut est 0. Ci-dessous, nous expliquons pourquoi vous aurez plusieurs clients gérés automatiquement pour clientId 0, ce que la documentation ci-dessus met en garde.
Une fois que votre fragment de connexion est associé à une FragmentActivity, il indique à cette activité de commencer à gérer une nouvelle instance de GoogleApiClient. Mais que se passe-t-il si FragmentActivity gère déjà une autre instance de GoogleApiClient? C'est à ce moment-là que vous obtenez l'erreur.
Il existe quelques scénarios possibles pouvant mener à cette situation liée à plusieurs GoogleApiClients-per-FragmentActivity.
Peut-être ajoutez-vous Fragment de connexion à une FragmentTransaction et appelez addToBackStack. Ensuite, l'utilisateur appuie en arrière, puis plus tard, le fragment de connexion est réattaché. Dans ce cas, les appels de méthode importants pour l'activité de connexion sont onCreateView -> onDestroyView -> onCreateView, comme indiqué ici:
Cela est problématique car le deuxième appel à Login.onCreateView tente de faire en sorte que FragmentActivity gère un deuxième GoogleApiClient.
Si j'étais vous, je penserais sérieusement à créer le GoogleApiClient dans l'activité plutôt que dans des fragments. Vous pouvez ensuite faire le travail nécessitant GoogleApiClient dans l'activité ou continuer à le faire dans le fragment de connexion après avoir récupéré le GoogleApiClient de l'activité comme suit:
private GoogleApiClient googleApiClient;
@Override
void onAttach(Activity activity) {
super.onAttach(activity);
googleApiClient = activity.getGoogleApiClient();
}
@Override
void onDetach() {
super.onDetach();
googleApiClient = null;
}
Je vous suggère d’initialiser votre mGoogleApiClient
dans onCreate()
au lieu de dans onCreateView()
.
Comme indiqué par @vlazzle , onCreateView()
peut être appelé plusieurs fois au cours de la vie d'une seule variable Activity
.
Vous devriez appeler stopAutoManage()
dans la méthode onDestroy()
de votre fragment de la manière suivante:
@Override
public void onDestroy() {
super.onDestroy();
mGoogleApiClient.stopAutoManage(getActivity());
mGoogleApiClient.disconnect();
}