Why doesn't Android Facebook interface work with Fragments?

烈酒焚心 提交于 2019-11-30 19:05:32

问题


I'm switching some Android Facebook code from an Activity to a Fragment. Prior to the switch everything worked fine, but now the onComplete() callback is not being executed.

Does the Facebook code not work with Fragments, or am I doing something wrong?

Here's the original code (in a SherlockActivity):

if (!mFacebook.isSessionValid()) {
    mFacebook.authorize(MyActivity.this, permissions, new DialogListener() {
        @Override
        public void onComplete(Bundle values) { ... }    // CALLED AS EXPECTED
    }
}

And here's the new code (in a SherlockFragment):

if (!mFacebook.isSessionValid()) {
    mFacebook.authorize(getActivity(), permissions, new DialogListener() {
        @Override
        public void onComplete(Bundle values) { ... }    // DOES NOT GET CALLED
    }
}

Both the Activity and the Fragment include the same onActivityResult() as required by Facebook:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    mFacebook.authorizeCallback(requestCode, resultCode, data);
}

Thanks for your help!

EDIT: A similar question is asked here, where the accepted answer is to change the Fragment to a FragmentActivity. But I don't see how this helps, as then it's no longer a Fragment (which I need for other reasons). Suggestions?

EDIT 2: I rolled my own solution. See below.


回答1:


As far as I could determine, the Facebook auth API does not support Fragments. Specifically, the onComplete() callback from the Facebook authorize() call works with Activities, but not with Fragments.

So I put together a simple workaround for Fragments. The solution depends on the fact that onActivityResult() is also called in the parent Activity when the authorize() call completes, so you can use it to set up a separate callback mechanism for the Fragment.

First, set up a variable in the parent Activity to carry the target Fragment's name, say

TargetFragment mTargetFragment;

You can initialize it when the Fragment is first instantiated like this:

@Override
public void onAttachFragment(Fragment fragment) {
    super.onAttachFragment(fragment);

    String fragmentSimpleName = fragment.getClass().getSimpleName();

    if (fragmentSimpleName.equals("TargetFragment"))
        mTargetFragment = (TargetFragment)fragment;        
}

Then add a couple of lines to the onActivityResult() function:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (mTargetFragment != null)       
        mTargetFragment.myCallBack(requestCode, resultCode, data);
}

Now you can just mimic the code you would ordinarily put in the onComplete() callback in the new myCallBack() function:

public void myCallBack(int requestCode, int resultCode, Intent data) {
    mFacebook.authorizeCallback(requestCode, resultCode, data);

    // other code from your onComplete() function ...
}

I hope this can help someone else. Cheers!




回答2:


I have downloaded the latest version of Facebook SDK and I have the same problem, the solution of gcl1 works fine but I have to do more things on activity result so I have made this on the parent activity:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (mTargetFragment != null) {
        mTargetFragment.onActivityResult(requestCode, resultCode, data);
    }
}



回答3:


Facebook SDK don't works with Fragment, but works with FragmentActivity. So you need:

  1. Catch the FB login info in onActivityResult() in your parent FragmentActivity.
  2. Pass activity results to your child Fragment

example:

1.

public class MainActivity extends FragmentActivity(){


/* catch FACEBOOK login info and call onFBLoginActivityResult() to pass it to FacebookFrragment*/
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

       android.support.v4.app.FragmentManager fm =   getSupportFragmentManager();
       FacebookFragment fbfragment= (FacebookFragment ) fm.findFragmentByTag("facebookfragment");
       selectPKEConfigFragment.onFBLoginActivityResult(requestCode, resultCode, data);

    }

}

2.

public class FacebookFragment extends Fragment{

        @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container, 
                Bundle savedInstanceState) {
        // ........... 

         // start Facebook Login

                    Session.openActiveSession(getActivity(), true, new Session.StatusCallback() {

                      // callback when session changes state
                      @Override
                      public void call(Session session, SessionState state, Exception exception) {
                        if (session.isOpened()) {
                          // make request to the /me API
                          Request.executeMeRequestAsync(session, new Request.GraphUserCallback() {

                            // callback after Graph API response with user object
                            @Override
                            public void onCompleted(GraphUser user, Response response) {
                              if (user != null) {
                               // TextView welcome = (TextView) findViewById(R.id.welcome);
                               // welcome.setText("Hello " + user.getName() + "!");
                                  Log.i(TAG,"User: " + user.getName());
                              }
                              else  Log.i(TAG,"User: null");
                            }
                          });
                        }
                        else Log.i(TAG,"session closed");
                      }


                    });

            }

        /*
         * replace onActivityResult
         */
        public void onFBLoginActivityResult(int requestCode, int resultCode, Intent data){
             Log.i(TAG,"Activity result SelectPKEConfig");
            Session.getActiveSession().onActivityResult(getActivity(), requestCode, resultCode, data);
        }



回答4:


Actually if you look at Facebook Docs for Android you'll see the login example uses fragment in it.

There is LoginButton widget that Facebook SDK provides and it has a method called setFragment and you pass the target fragment that you want to use login functionality with.

In your fragment layout

Add the login button that Facebook SDK provides.

        <com.facebook.widget.LoginButton
            android:id="@+id/facebook_login_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="30dp" />

In your fragment

Create UiLifecycleHelper and StatusCallback objects in your fragment.

private UiLifecycleHelper uiHelper;
private Session.StatusCallback callback = new Session.StatusCallback() {
    @Override
    public void call(Session session, SessionState state, Exception exception) {
        onSessionStateChange(session, state, exception);
    }
};

Add a method to handle the user state changes.

private void onSessionStateChange(Session session, SessionState state, Exception exception) {
    if (state.isOpened()) {
        Log.i("LoginFragment", "Logged in...");
        Log.i("LoginFragment", session.getAccessToken());
        doAnythingWithTheFacebookToken(session.getAccessToken());
    } else if (state.isClosed()) {
        // this part is called when user login fails
        Log.i("LoginFragment", "Logged out...");
    }
}

Override the fragment lifecycle methods

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    uiHelper = new UiLifecycleHelper(getActivity(), callback);
    uiHelper.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    // inflate your fragment view

    facebookLoginButton = (LoginButton) view.findViewById(R.id.facebook_login_button);
    facebookLoginButton.setFragment(this);
}

@Override
public void onResume() {
    super.onResume();
    // For scenarios where the main activity is launched and user
    // session is not null, the session state change notification
    // may not be triggered. Trigger it if it's open/closed.
    Session session = Session.getActiveSession();
    if (session != null &&
            (session.isOpened() || session.isClosed())) {
        onSessionStateChange(session, session.getState(), null);
    }

    uiHelper.onResume();
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    uiHelper.onActivityResult(requestCode, resultCode, data);
}

@Override
public void onPause() {
    super.onPause();
    uiHelper.onPause();
}

@Override
public void onDestroy() {
    super.onDestroy();
    uiHelper.onDestroy();
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    uiHelper.onSaveInstanceState(outState);
}

Result

Normally you'd need to override onActivityResult in your activity but calling setFragment() on Facebook Login Button allows your fragment to receive the result in its own onActivityResult.

If you want to use a different button (your own button for example):

  • hide the facebookLoginButton in layout

  • call performClick() on facebookLoginButton inside the onclick listener of your actual button

That's it.




回答5:


We don't need to configure onActivityResult inside main activity of fragment class and inside fragment to. Just put below code inside main activity that contains your fragment and do rest of facebook sdk code inside fragment ...its so simple.

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) 
    {
        super.onActivityResult(requestCode, resultCode, data);
        Session.getActiveSession().onActivityResult(ChatScreen.this, requestCode,
                resultCode, data);
    }  


来源:https://stackoverflow.com/questions/10943392/why-doesnt-android-facebook-interface-work-with-fragments

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!