Error in Fragment: “Already managing a GoogleApiClient with id 0”

后端 未结 10 1848
独厮守ぢ
独厮守ぢ 2020-12-13 08:16

Everything works right the first time, if you launch a second time you see this error:

FATAL EXCEPTION: main
Process         


        
相关标签:
10条回答
  • 2020-12-13 08:41

    The checked answer will not work if you use Login fragment in an Activity multiple times, because adding the fragment sequentially in a short time will lead the same crash. Android sometimes mixes lifecycle of Fragments added in an Activity.

    So I advice you to do mGoogleApiClient staff in a separate abstract Activity, and make all activities adding Login fragment extend this Activity.

    I have managed to get rid of this crash by creating this abstract Activity below, just copy paste it to your project:

    abstract class LoginableActivity : BaseActivity() {
    
        lateinit var googleApiClient: GoogleApiClient
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestIdToken(getString(R.string.fcm))
                .requestEmail()
                .build()
    
            googleApiClient = GoogleApiClient.Builder(this)
                .enableAutoManage(this, 1, null)
                .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                .build()
        }
    
        override fun onStart() {
            super.onStart()
            if (!googleApiClient.isConnected && !googleApiClient.isConnecting) {
                googleApiClient.connect()
            }
        }
    
        override fun onStop() {
            super.onStop()
            if (googleApiClient.isConnected) {
                googleApiClient.stopAutoManage(this)
                googleApiClient.disconnect()
            }
        }
    }
    

    After you moved googleApiClient to LoginableActivity you can access googleApiClient from Login fragment like this (let's do it with Java):

    final Activity = getActivity();
    if (activity instanceof LoginableActivity) {
        final GoogleApiClient googleApiClient = ((LoginableActivity) activity).googleApiClient;
    }
    
    0 讨论(0)
  • 2020-12-13 08:43

    I faced a similar issue when I placed a login button in two different Fragments belonging to the same Activity.

    I solved this issue by assigning different ids to each automatically-managed GoogleApiClient.

    For example, in Fragment 1, while creating my GoogleApiClient object I assigned 0 as the id:

    mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
                        .enableAutoManage(getActivity(), 0, this /* OnConnectionFailedListener */)
                        .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                        .build();
    

    In Fragment 2, while creating my GoogleApiClient object I assigned 1 as the id:

    mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
                        .enableAutoManage(getActivity(), 1, this /* OnConnectionFailedListener */)
                        .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                        .build();
    
    0 讨论(0)
  • 2020-12-13 08:46

    I suggest that you initialize your mGoogleApiClient in onCreate() instead of in onCreateView().

    As pointed out by @vlazzle, onCreateView() can be called more than once during a single Activity's lifespan.

    0 讨论(0)
  • 2020-12-13 08:48

    You should call stopAutoManage() in the onPause() method of your Fragment:

    @Override
    public void onPause() {
        super.onPause();
        mGoogleClient.stopAutoManage(getActivity());
        mGoogleClient.disconnect();
    }
    
    0 讨论(0)
  • 2020-12-13 08:48

    The official doc for enableAutoManage says this:

    At any given time, only one auto-managed client is allowed per id. To reuse an id you must first call stopAutoManage(FragmentActivity) on the previous client.

    Your code is using the version of enableAutoManage without a clientId parameter, so it's defaulting to 0. Below I explain why you will have multiple auto-managed clients for clientId 0, which is what the above documentation is warning against.

    After your Login Fragment is attached to a FragmentActivity, it tells that activity to start managing a new instance of GoogleApiClient. But what if the FragmentActivity is already managing another instance of GoogleApiClient? That's when you get the error.

    There are a few possible scenarios that can lead up to this multiple-GoogleApiClients-per-FragmentActivity situation.

    • The FragmentActivity has another Fragment in addition to Login that creates a GoogleApiClient and also asks the FragmentActivity to manage it.
    • The FragmentActivity itself creates a GoogleApiClient and starts managing it before Login Fragment is attached to the FragmentActivity.
    • Maybe you add Login Fragment in a FragmentTransaction and you call addToBackStack. Then the user taps back, then later somehow the Login Fragment is re-attached. In this case, the important Login Activity method calls are onCreateView -> onDestroyView -> onCreateView as shown here:

    This is problematic because the second call to Login.onCreateView tries to have FragmentActivity manage a second GoogleApiClient.

    If I were you, I'd seriously consider creating the GoogleApiClient in the activity instead of in any fragments. Then you could either do the work that requires GoogleApiClient in the Activity, or continue to do it in Login Fragment after getting the GoogleApiClient from the Activity like so:

    private GoogleApiClient googleApiClient;
    
    @Override
    void onAttach(Activity activity) {
        super.onAttach(activity);
        googleApiClient = activity.getGoogleApiClient();
    }
    
    @Override
    void onDetach() {
        super.onDetach();
        googleApiClient = null;
    }
    
    0 讨论(0)
  • 2020-12-13 08:51

    Try to use your mGoogleApiClient from your activity. if you have declared GoogleApiClient on your activity, then you can't re-declared on your fragment. instead, re-use variable in that activity from fragment

    mGoogleApiClientInFragment = ((Youractivityclass)getActivity()).mGoogleApiClient;
    

    replace YouractivityClass with your activity of your fragment, and make sure set your mGoogleApiClient field in your activity to public

    0 讨论(0)
提交回复
热议问题