OnBackPress 显示的片段更新失败

OnBackPress the fragment to be shown fails to update

假设我在片段 A 中,然后移动到 B,然后使用返回按钮 returns 到 A。 在 activity 中,我正在执行以下覆盖:

@Override
public void onBackPressed(){
    FragmentManager fm = getSupportFragmentManager();
    Fragment frag = fm.findFragmentByTag(Consts.A);
    if (frag != null){
        Log.d(Consts.TAGS.ACTIVITY_ORDER,"");
        fm.beginTransaction().remove(frag).commit();
        fm.popBackStack();
    }
}

显示 B 时是这样的:

                FragmentManager fm = getActivity().getSupportFragmentManager();
            Fragment f = BFragment.newInstance(Consts.B);
            fm.beginTransaction()
                    .replace(R.id.rl_content,
                            f,
                            Consts.B)
                    .addToBackStack(null)  
                    .commit();

现在,一旦我们执行popBackStack(),A中将执行哪个方法(如果有的话)? 如果none,我们如何在返回后立即更改A的数据模型或UI组件(例如键盘或TextView)?是否依赖于组件?

R.id.rl_content 是容器。 请考虑两种情况: 1. A在R.id.rl中,正在被替换 2. A 不在 R.id.rl 中且未被替换

如果您总是从片段 B 返回到片段 A,反之亦然,我建议在片段本身内使用此解决方案。

@Override
    public void onResume() {
        super.onResume();

        Fragment f = AFragment.newInstance(Consts.A);

        if(getView() == null){
            return;
        }
        getView().setFocusableInTouchMode(true);
        getView().requestFocus();
        getView().setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){
                    FragmentTransaction trans = getFragmentManager().beginTransaction();
                    trans.replace(R.id.rl_content, f);
                    trans.addToBackStack(null);
                    trans.commit();
                    return true;
                }
                return false;
            }
        });
    }

您可以使用相同的代码自由地从 B 移动到 A 以及从 A 移动到 B。如果你想要一个更动态的方法,例如你想从 Fragment A 转到 Fragment C,或从 Fragment B 转到 Fragment C,然后当你按返回时返回到堆栈上的前一个片段。我的目标是使用 Kyle Falconer's Solution here

以防 link 死亡,我将 post 代码放在这里:

@Override
public void onBackPressed(){
    FragmentManager fm = getFragmentManager();
    if (fm.getBackStackEntryCount() > 0) {
        Log.i("MainActivity", "popping backstack");
        fm.popBackStack();
    } else {
        Log.i("MainActivity", "nothing on backstack, calling super");
        super.onBackPressed();  
    }
}

我没有测试第二种解决方案,但使用第一种。

有几种方法可以更改 A 的数据模型或 UI 组件。

情况1:当A在R.id.rl_content中被B替换时。在这种情况下,您可以简单地更新所需的模型或UI在片段 A 的 onCreateView。

情况2:当A没有被替换时。在这种情况下,片段 A 不知道何时更新其视图。在 activity 的 onBackpressed() 中,如果正在弹出片段 B,您可以调用片段 A 的 updateView() 方法。

@Override 
public void onBackPressed(){ 
    FragmentManager fm = getSupportFragmentManager(); 
    FragmentB fragmentB = (FragmentB)fm.findFragmentByTag(Consts.B); 
    if (fragmentB != null){ 
        Log.d(Consts.TAGS.ACTIVITY_ORDER,"");
        fm.beginTransaction().remove(fragmentB).commit(); 
        fm.popBackStack(); 
        FragmentA fragmentA = (FragmentA)fm.findFragmentByTag(Consts.A);
        if (fragmentA != null) {
             fragmentA.updateView();
        }
    } 
} 

编辑

我了解到您还想处理隐藏键盘等场景。 为此,您可能希望将 backpress 事件传递给各个片段。有点像这样:

@Override 
public void onBackPressed(){ 
    FragmentManager fm = getSupportFragmentManager(); 
    FragmentB fragmentB = (FragmentB)fm.findFragmentByTag(Consts.B); 
    if (fragmentB != null){ 
            if (!fragmentB.onBackPress()) {
                 // This means fragment B doesn't want to consume backpress therefore remove it.
                 Log.d(Consts.TAGS.ACTIVITY_ORDER,"");
                 fm.beginTransaction().remove(fragmentB).commit(); 
                 fm.popBackStack(); 
                 FragmentA fragmentA = (FragmentA)fm.findFragmentByTag(Consts.A);
                 if (fragmentA != null) {
                     fragmentA.updateView();
                 }
            }
        } 
    } 

然后在您的 Fragment B 中创建一个 onBackPress 函数,如下所示:

public boolean onBackPressed() {
  // if keyboard is showing then hide it here and return true to consume the back press event or else return false to dismiss this fragment. 
}