【问题标题】:Fragments still added to backstack without calling addToBackStack, why?片段仍然添加到 backstack 而不调用 addToBackStack,为什么?
【发布时间】:2014-01-28 13:58:59
【问题描述】:

我正在制作我的片段更换器助手类,但我遇到了一些问题。

我叫它FragmentChanger

它有一个fragmentContainer,它是一个ViewGroup,它包含我想展示的所有片段。

我自己做了replace(Fragment fragmentToChange, boolean needSaveToBackStack)

函数是:

  • 从 fragmentContainer 中删除旧片段
  • 向 fragmentContainer 添加新片段
  • 可选择保存到 backStack,needSaveToBackStacktrue 还是 false

错误如下:

如果我使用替换功能并保存到 backStack,它可以正常工作,我可以使用设备的后退按钮来回退并返回到以前添加的片段,这就像一个魅力。

但是当我想替换一个片段 withOUT 保存到 backStack 时,我的代码有问题,因为当我后退时,我可以在屏幕上看到我的片段未添加到 backStack,并且 我还可以同时看到另一个先前添加的片段!

所以我可以同时看到 2 个片段,像这样:

这是我的代码:

//It is my helper class to handle replacing fragments.
public class FragmentChanger {

// fragmentTransaction
FragmentTransaction fragmentTransaction;

// the container for fragments
ViewGroup fragmentContainer;

// activity ofc
Activity act;

// Ctr: adding a default fragment to be the first so we can see it at app
// start
public FragmentChanger(Activity act, ViewGroup container, Fragment startingFragment) {

    this.act = act;
    this.fragmentContainer = container;
    fragmentTransaction = act.getFragmentManager().beginTransaction();
    fragmentTransaction.add(container.getId(), startingFragment, startingFragment.getClass().getSimpleName());
    fragmentTransaction.addToBackStack(startingFragment.getClass().getSimpleName());
    fragmentTransaction.commit();

}

// Replacing a fragment with an other one
public void replace(Fragment fragmentToChange, boolean needSaveToBackStack) {

    fragmentTransaction = act.getFragmentManager().beginTransaction();

    // replacing old fragment to the new one!
    fragmentTransaction.replace(fragmentContainer.getId(), fragmentToChange, fragmentToChange.getClass().getSimpleName());

    // Some null checking, and if the new fragment is NOT equals the current
    // fragment
    if (getCurrentFragment() != null && getCurrentFragment() != fragmentToChange) {

        /*** Important** because something here is wrong ***/

        // only addToBackStack when i want it, when needSaveToBackStack =
        // true!
        if (needSaveToBackStack) {
            fragmentTransaction.addToBackStack(fragmentToChange.getClass().getSimpleName());
        }
    }

    // commiting changes
    fragmentTransaction.commit();

}

// getting current Fragment
private Fragment getCurrentFragment() {

    try {

        FragmentManager fragmentManager = act.getFragmentManager();
        String fragmentTag = fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount() - 1).getName();
        Fragment currentFragment = act.getFragmentManager().findFragmentByTag(fragmentTag);
        return currentFragment;

    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}

// Logging the back stack
public void logBackStack() {

    Log("Logging back stack:", "=============");

    FragmentManager fragmentManager = act.getFragmentManager();
    int stackSize = fragmentManager.getBackStackEntryCount();

    Log("Fragments count on the stack: ", stackSize + "");

    for (int i = 0; i < stackSize; i++) {
        String fragmentTag = fragmentManager.getBackStackEntryAt(i).getName();
        Log("Fragment on the stack: ", fragmentTag);
    }

}

private void Log(String str, String msg) {
    Log.i(str, msg);
}

}

这是我的 MainActivity,我在其中测试我的片段助手类:

public class MainActivity extends Activity implements OnClickListener {

// My 3 Fragment Classes, could be N other type,
// in this example I only got 3
FragmentA fragmentA;
FragmentB fragmentB;
FragmentC fragmentC;

// Button to add the fragments manually
Button addA, addB, addC;

// This is my activity's container, its a simple viewGroup
// could be anything that can hold fragments
ViewGroup fragmentContainer;

// This is my fragment changer helper class that need some revision by you
// guys
FragmentChanger fragmentChanger;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //defining my adding buttons
    addA = (Button)findViewById(R.id.addAbtn);
    addB = (Button)findViewById(R.id.addBbtn);
    addC = (Button)findViewById(R.id.addCbtn);

    //setting onclicklistenrs
    addA.setOnClickListener(this);
    addB.setOnClickListener(this);
    addC.setOnClickListener(this);

    // defining my main container, this will holds fragments
    fragmentContainer = (ViewGroup) findViewById(R.id.fragmentContainer);

    // defining my fragments, each of them got an Activity (this), a
    // Container (mainContainer), and a Layout ofc.
    fragmentA = new FragmentA(this, fragmentContainer, R.layout.fragment_a_layout);
    fragmentB = new FragmentB(this, fragmentContainer, R.layout.fragment_b_layout);
    fragmentC = new FragmentC(this, fragmentContainer, R.layout.fragment_c_layout);

    // defining my fragment changer with an activity(this), a
    // container(mainContent) and a starting fragment to show!
    fragmentChanger = new FragmentChanger(this, fragmentContainer, fragmentA);

}

@Override
public void onClick(View view) {

    if (view.equals(addA)) {

        //When adding fragmentA, i always want to save it to backstack
        fragmentChanger.replace(fragmentA, true);

    } else if (view.equals(addB)) {

        //I dont want to save to back stack when adding B
        //So if i press back button, i dont want to see fragmentB ever again.
        //(But i do see, this is the error.)
        fragmentChanger.replace(fragmentB, false);
    } else if (view.equals(addC)) {

        //When adding fragmentC, i always want to save it to backstack
        fragmentChanger.replace(fragmentC, true);
    }

    //After any modification on fragments, i log the backstack
    fragmentChanger.logBackStack();

}

}

Ps:如果我每次用我的帮助类替换 Fragment 时都记录堆栈,我可以清楚地看到 FragmentB 永远不会在 backStack 上。 那为什么如果我按下后退按钮会出现?

非常感谢任何建议,这是我第一次尝试将片段与我自己的帮助类一起使用,我想让它变得非常有用。

【问题讨论】:

  • 您是否只在示例中单击了 AddB 按钮?您的活动已开始,您只点击了“添加 B”?
  • 不,我按随机顺序推送所有这些。

标签: android android-fragments


【解决方案1】:

所以我发现你的代码有问题:

1) 您将FragmentBackStackEntry 的标签混合在一起。

String fragmentTag = fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount() - 1).getName();

所以在这里你得到BackStackEntry(不是Fragment)的标签,你在fragmentTransaction.addToBackStack()中添加或不添加。因此,您得到了错误的状态并将其用作当前片段。

2) 像在类字段中那样存储和重用片段通常不是一个好主意:FragmentA fragmentA;。它可能会导致状态和通货膨胀问题,如果您不想解决其他难题,最好在每笔交易中创建它们。

【讨论】:

  • 老实说,我不知道这真的是解决方案,但这个答案是最好的,赏金将在 1 天内结束,所以我不希望声誉“丢失”,所以就在这里。
【解决方案2】:

改变这一行

    fragmentTransaction.add(container.getId(), startingFragment, startingFragment.getClass().getSimpleName());

    fragmentTransaction.replace(container.getId(), startingFragment, startingFragment.getClass().getSimpleName());

【讨论】:

    【解决方案3】:

    尝试使用 FragmentTransacion.replace 方法替换片段,如链接here所示

    您也可以参考this 示例。这对我来说非常有效。

    【讨论】:

    • 如你所见,我是这样使用的:fragmentTransaction.replace(fragmentContainer.getId(), fragmentToChange, fragmentToChange.getClass().getSimpleName());
    【解决方案4】:

    首先在FragmentChanger 类的构造函数中,您将所有片段添加到您的后台堆栈中。因为您按顺序添加它们,所以它们被添加为 A,B,然后是 C。 以该顺序将它们添加到后台堆栈后,您将在其上进行更多事务。在初始化它们时,请避免将它们添加到后台堆栈。仅在执行实际按钮单击时添加/删除它们。

    你的代码中有很多替换,所以我不知道如何真正解决这个问题,但我可以大致概述一下你应该做什么。

    如果你想在 backStack 中添加一个片段,那么请执行 a.replace(params ).addToBackStack(Tag)

    如果您不想添加特定片段,请完全跳过 addToBackStack(Tag) 行。

    你的getCurrentFragment()也可以改为

    Fragment currentFrag=getFragmentManager().findFragmentById(R.id.fragment_container);

    在此处阅读此ANSWER 以获得更好的解释,以及此ANSWER

    【讨论】:

    • "首先在 FragmentChanger 类的构造函数中,您将所有片段添加到后台堆栈中。" 不,我不这样做。
    猜你喜欢
    • 1970-01-01
    • 2015-06-13
    • 2019-08-25
    • 1970-01-01
    • 1970-01-01
    • 2013-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多