我正在制作片段更换器助手类,但我遇到了一些问题。
我称之为FragmentChanger
它有一个fragmentContainer
,它是一个ViewGroup
,它包含我想要显示的所有片段。
我已经制作了自己的replace(Fragment fragmentToChange, boolean needSaveToBackStack)
功能是:
needSaveToBackStack
为true
或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:我可以清楚地看到,如果我每次用我的助手类替换片段时都记录堆栈,那么fragmentB永远不会出现在backStack上。那么为什么我按下按钮会出现?
我非常感谢任何建议,这是我第一次尝试使用我自己的帮助类片段,我希望它能够大大提高。
答案 0 :(得分:2)
所以我发现你的代码错误了:
1)您将Fragment
和BackStackEntry
的标签混合在一起。
String fragmentTag = fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount() - 1).getName();
所以,您在此处获得BackStackEntry
(不是Fragment
)的标记,您可以在fragmentTransaction.addToBackStack()
中添加或不添加标记。因此,您将获得错误的状态并将其用作当前片段。
2)像在类字段中一样存储和重用片段通常不是一个好主意:FragmentA fragmentA;
。它可能会导致状态和通货膨胀问题,如果你不想解决其他难题,最好在每笔交易中创建它们。
答案 1 :(得分:1)
答案 2 :(得分:1)
更改此行
fragmentTransaction.add(container.getId(), startingFragment, startingFragment.getClass().getSimpleName());
到
fragmentTransaction.replace(container.getId(), startingFragment, startingFragment.getClass().getSimpleName());
答案 3 :(得分:0)
首先,在FragmentChanger
类的构造函数中,您将所有片段添加到backstack中。因为你要添加它们,以便它们被添加为A,B,然后是C.
按顺序将它们添加到backstack后,您将在其上执行更多事务。在初始化它们时,请避免将它们添加到Backstack中。只在实际按钮点击时添加/删除它们。
你的代码中有很多替代品,所以我不知道如何真正解决这个问题,但我可以概括一下你应该做些什么。
如果要将片段添加到backStack,请执行.replace(params ).addToBackStack(Tag)
如果您不想添加特定片段,请完全跳过addToBackStack(Tag)
行。
您的getCurrentFragment()
也可以更改为
Fragment currentFrag=getFragmentManager().findFragmentById(R.id.fragment_container);