【问题标题】:Why doesn't Android Facebook interface work with Fragments?为什么 Android Facebook 界面不能与 Fragments 一起使用?
【发布时间】:2012-06-08 05:14:06
【问题描述】:

我正在将一些 Android Facebook 代码从 Activity 切换到 Fragment。在切换之前一切正常,但现在 onComplete() 回调没有被执行。

Facebook 代码是否不适用于 Fragments,还是我做错了什么?

这是原始代码(SherlockActivity):

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

这是新代码(在 SherlockFragment 中):

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

Activity 和 Fragment 都包含 Facebook 要求的相同 onActivityResult():

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

感谢您的帮助!

编辑:问了一个类似的问题here,接受的答案是将Fragment 更改为FragmentActivity。但我不明白这有什么帮助,因为它不再是Fragment(我需要它出于其他原因)。有什么建议吗?

编辑 2:我推出了自己的解决方案。见下文。

【问题讨论】:

    标签: android android-fragments actionbarsherlock facebook-android-sdk fragmentpageradapter


    【解决方案1】:

    据我所知,Facebook auth API 不支持片段。具体来说,来自 Facebook authorize() 调用的 onComplete() 回调适用于 Activity,但不适用于 Fragments

    所以我为 Fragments 制定了一个简单的解决方法。解决方案取决于onActivityResult()authorize() 调用完成时也会在父Activity 中调用,因此您可以使用它来设置单独的回调 片段的机制。

    首先,在父Activity中设置一个变量来携带目标Fragment的名称,比如说

    TargetFragment mTargetFragment;
    

    您可以在第一次实例化 Fragment 时对其进行初始化,如下所示:

    @Override
    public void onAttachFragment(Fragment fragment) {
        super.onAttachFragment(fragment);
    
        String fragmentSimpleName = fragment.getClass().getSimpleName();
    
        if (fragmentSimpleName.equals("TargetFragment"))
            mTargetFragment = (TargetFragment)fragment;        
    }
    

    然后在 onActivityResult() 函数中添加几行代码:

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

    现在您可以在新的 myCallBack() 函数中模仿通常放在 onComplete() 回调中的代码:

    public void myCallBack(int requestCode, int resultCode, Intent data) {
        mFacebook.authorizeCallback(requestCode, resultCode, data);
    
        // other code from your onComplete() function ...
    }
    

    我希望这可以帮助其他人。干杯!

    【讨论】:

    • 太有帮助了!感谢您对此进行调查!
    • 嗨,我正在尝试这个解决方案,但我在 myCallback 函数中的 facebook.authorizeCallback 上得到了 NetworkOnMainThreadException。谢谢!
    • 我不确定 authorizeCallback() 是否真的进行网络事务,但如果是这样,您需要将其移出任何面向用户的 Activity(使用 AsyncTask 之类的东西)。这是因为 Android 有一个严格模式,可以防止面向用户的线程执行网络事务。为了快速开发解决方法,您可以在 Activity 的 onCreate() 调用中添加以下两行: StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy);请务必在生产前删除解决方法并修复。祝你好运!
    • 这对我有用。我正在实现 Facebook DialogListener 的 Fragment。在 Facebook authorize() 调用期间,Fragment 和父 Activity 被销毁。从 authorize() 调用返回后,Activity/Fragment 被重新创建,但旧的 Fragment 得到了回调。由于它不再附加到 Activity,因此与 UI 相关的操作可以在没有错误的情况下发生。所以我切换了代码,让 Activity 成为 DialogListener。当发生回调时,我让 Activity 查找当前 Fragment 并将调用委托给它。现在一切正常!
    【解决方案2】:

    我已经下载了最新版本的 Facebook SDK,我也遇到了同样的问题,gcl1 的解决方案工作正常,但我必须对活动结果做更多​​的事情,所以我在父活动上做了这个:

    @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 不适用于 Fragment,但适用于 FragmentActivity。 所以你需要:

      1. 在父 FragmentActivity 的 onActivityResult() 中捕获 FB 登录信息。
      2. 将活动结果传递给您的子 Fragment

      示例:

      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】:

        实际上,如果您查看Facebook Docs for Android,您会看到登录示例在其中使用了片段。

        Facebook SDK 提供了 LoginButton 小部件,它有一个名为 setFragment 的方法,您可以传递要使用登录功能的目标片段。

        在您的片段布局中

        添加 Facebook SDK 提供的登录按钮。

                <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" />
        

        在你的片段中

        在您的片段中创建 UiLifecycleHelperStatusCallback 对象。

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

        添加处理用户状态变化的方法。

        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
        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);
        }
        

        结果

        通常您需要在活动中覆盖 onActivityResult,但在 Facebook 登录按钮上调用 setFragment() 可以让您的片段以自己的 接收结果onActivityResult

        如果您想使用不同的按钮(例如您自己的按钮):

        • 在布局中隐藏 facebookLoginButton

        • 在实际按钮的 onclick 侦听器内的 facebookLoginButton 上调用 performClick()

        就是这样。

        【讨论】:

        【解决方案5】:

        我们不需要在片段类的主要活动内部和片段内部配置onActivityResult。 只需将下面的代码放在包含您的片段的主要活动中,然后在片段中执行其余的 facebook sdk 代码……就这么简单。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-03-09
          • 2021-06-14
          • 2012-10-09
          • 2020-03-18
          • 2017-11-21
          • 2019-04-11
          相关资源
          最近更新 更多