Android Fragment结合Navigation Component实现Facebook登录异常排查
问题描述
在Activity中实现Facebook登录功能完全正常,但迁移到使用Navigation Component的Fragment后出现异常:点击Facebook登录按钮能弹出授权界面,但点击「继续」后,loginWithFacebook()方法内的Log.i()日志没有触发,回调逻辑未执行。
Fragment代码
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentLoginBinding.inflate(inflater, container, false); // facebook callback callbackManager = CallbackManager.Factory.create(); LoginManager.getInstance().registerCallback(callbackManager, new FacebookCallback<LoginResult>() { @Override public void onSuccess(LoginResult loginResult) { // App code loginWithFacebook(loginResult); } @Override public void onCancel() { // App code } @Override public void onError(FacebookException exception) { // App code Log.e("Login With facebook", "onError: ", exception); } }); binding.btnRegisterFacebook.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { LoginManager.getInstance().logInWithReadPermissions(requireActivity(), Arrays.asList("public_profile")); } }); return binding.getRoot(); } @Override public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { callbackManager.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data); } private void loginWithFacebook(LoginResult loginResult) { // here we will get access token and save data to server AccessToken accessToken = loginResult.getAccessToken(); GraphRequest request = GraphRequest.newMeRequest( accessToken, new GraphRequest.GraphJSONObjectCallback() { @Override public void onCompleted( JSONObject object, GraphResponse response) { try { String name = object.getString("name"); String id = object.getString("id"); // save to server Log.i("Facebook auth",id); Log.i("Facebook auth",name); } catch (JSONException e) { Log.e("Login With facebook", "onCompleted: ", e); throw new RuntimeException(e); } // Application code } }); Bundle parameters = new Bundle(); parameters.putString("fields", "id,name,link"); request.setParameters(parameters); request.executeAsync(); }
宿主Activity代码
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { Fragment navhost = getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment); navhost.onActivityResult(requestCode,resultCode,data); super.onActivityResult(requestCode, resultCode, data); }
排查与解决
问题核心是Activity到Fragment的onActivityResult结果分发逻辑错误,以及Fragment回调的生命周期稳定性问题,按以下步骤修复:
修正宿主Activity的结果分发逻辑
直接调用navhost.onActivityResult()无法将结果传递到当前显示的子Fragment,需要通过NavHostFragment的子Fragment管理器分发。同时要先调用super.onActivityResult():@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); Fragment navHost = getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment); if (navHost != null) { // 遍历NavHost下的子Fragment,分发结果 for (Fragment fragment : navHost.getChildFragmentManager().getFragments()) { fragment.onActivityResult(requestCode, resultCode, data); } } }确保CallbackManager是Fragment成员变量
避免在onCreateView中局部声明callbackManager,防止Fragment重建时回调实例丢失,将其声明为Fragment的全局成员:public class LoginFragment extends Fragment { private FragmentLoginBinding binding; // 全局成员变量 private CallbackManager callbackManager; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentLoginBinding.inflate(inflater, container, false); callbackManager = CallbackManager.Factory.create(); // 后续注册回调逻辑... return binding.getRoot(); } }改用LoginButton的Fragment绑定方式(推荐)
对于Fragment场景,Facebook官方推荐直接使用LoginButton并调用setFragment(this),无需手动处理onActivityResult分发,简化逻辑:@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentLoginBinding.inflate(inflater, container, false); callbackManager = CallbackManager.Factory.create(); LoginButton loginButton = binding.btnRegisterFacebook; // 将按钮与当前Fragment绑定 loginButton.setFragment(this); loginButton.setReadPermissions(Arrays.asList("public_profile")); loginButton.registerCallback(callbackManager, new FacebookCallback<LoginResult>() { @Override public void onSuccess(LoginResult loginResult) { loginWithFacebook(loginResult); } @Override public void onCancel() {} @Override public void onError(FacebookException exception) { Log.e("Login With facebook", "onError: ", exception); } }); return binding.getRoot(); }
内容的提问来源于stack exchange,提问作者Mohamed Hossam
相关产品推荐
相关产品推荐

