引言:這篇文章,記錄了下FragmentTransaction的使用注意事項(xiàng),和分析了下addToBackStack實(shí)際作用于誰。
public class MainActivity extends AppCompatActivity implements ItemFragment.OnListFragmentInteractionListener{
FragmentTransaction fragmentTransaction;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.container, BlankFragment.newInstance("",""), "blank");
fragmentTransaction.add(R.id.container, BlankFragment2.newInstance("",""), "list");
// fragmentTransaction.addToBackStack("blank");
// fragmentTransaction.addToBackStack("list");
fragmentTransaction.addToBackStack("cccc");
fragmentTransaction.commit();
}
@Override
public void onListFragmentInteraction(DummyContent.DummyItem item) {
}
@OnClick({R.id.button1, R.id.button2})
protected void onClick(View v){
switch (v.getId()){
case R.id.button1:
getSupportFragmentManager().popBackStack();
break;
case R.id.button2:
Toast.makeText(this, "button2", Toast.LENGTH_LONG).show();
FragmentTransaction f = getSupportFragmentManager().beginTransaction();
f.replace(R.id.container, ItemFragment.newInstance(10), "list");
f.addToBackStack("list");
f.commit();
// fragmentTransaction.commit();
/* getSupportFragmentManager().beginTransaction().add(R.id.container, ItemFragment.newInstance(10), "list");
getSupportFragmentManager().beginTransaction().addToBackStack("list");
getSupportFragmentManager().beginTransaction().commit();*/
break;
}
}
}
1.FragmentTransaction注意的地方
1.每次fragmentManager.beginTransaction()得到的都是一個(gè)新實(shí)例。像下面對FragmentTransaction改動(dòng)的代碼是不會(huì)生效的。
getSupportFragmentManager().beginTransaction().add(R.id.container, ItemFragment.newInstance(10), "list");
getSupportFragmentManager().beginTransaction().addToBackStack("list");
getSupportFragmentManager().beginTransaction().commit();
2.每次對FragmentTransaction更改后需要commit來執(zhí)行。但是這里有個(gè)要注意的地方就是,每個(gè)FragmentTransaction實(shí)例commit其實(shí)只能執(zhí)行一次。如果將上圖中的fragmentTransaction保存為全局后,當(dāng)?shù)谝淮蝐ommit后。在其他地方再去調(diào)用commit()就會(huì)報(bào)錯(cuò)(比如我在button2里去再次調(diào)用)。
protected void onCreate(Bundle savedInstanceState) {
...
fragmentTransaction.commit();
}
@OnClick({R.id.button1, R.id.button2})
protected void onClick(View v){
switch (v.getId()){
...
case R.id.button2:
...
fragmentTransaction.commit();
...
}
...
所以說第一次更改Fragment時(shí),務(wù)必將所有的操作做完,再commit。
2.addToBackStack與popBackStack
addToBackStack其實(shí)針對的是fragmentTransaction。而非是具體的fragment。分析如下:(R.id.container是一個(gè)垂直的線性布局)從上圖調(diào)用addToBackStack部分代碼來看,我開始使用
fragmentTransaction.add(R.id.container, BlankFragment.newInstance("",""), "blank");
fragmentTransaction.add(R.id.container, BlankFragment2.newInstance("",""), "list");
fragmentTransaction.addToBackStack("list");
fragmentTransaction.commit();
當(dāng)我點(diǎn)擊button1,調(diào)用popBackStack()后,按照原先設(shè)想(addToBackStack是針對具體的fragment),那么應(yīng)該是BlankFragment2被彈出,消失。但實(shí)際結(jié)果是BlankFragment和BlankFragment2都消失了。
當(dāng)將addToBackStack("list")改成addToBackStack("blank"),結(jié)果依然是兩個(gè)fragment都消失了。
這時(shí)我就懷疑,其實(shí)addToBackStack針對的是具體的FragmentTransaction。既然addToBackStack針對的是FragmentTransaction,那么他的參數(shù)tag其實(shí)跟Fragment的tag是沒有任何關(guān)系的。所以我再次將addToBackStack("blank")改成addToBackStack("cccc")然后調(diào)用popBackStack()。發(fā)現(xiàn)結(jié)果依然是兩個(gè)fragment都消失了。從這就可以看出來addToBackStack是針對的具體的FragmentTransaction。
3.addToBackStack與replace
我們都知道addToBackStack會(huì)將FragmentTransaction加入回退棧中,此時(shí)當(dāng)前FragmentTransaction不再處于激活狀態(tài)時(shí),F(xiàn)ragment并不會(huì)被銷毀。當(dāng)我們想對同一容器疊加多個(gè)Fragment,實(shí)現(xiàn)動(dòng)態(tài)添加新Fragment同時(shí)還能back退回到前一個(gè)Fragment。這個(gè)addToBackStack添加的位置是有講究的。代碼如下:
protected void onCreate(Bundle savedInstanceState) {
...
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.addToBackStack("cccc");
fragmentTransaction.commit();
}
@OnClick({R.id.button1, R.id.button2})
protected void onClick(View v){
switch (v.getId()){
case R.id.button1:
getSupportFragmentManager().popBackStack();
...
case R.id.button2:
...
FragmentTransaction f = getSupportFragmentManager().beginTransaction();
f.replace(R.id.container, BlankFragment2.newInstance("第二層",""), "list");
// f.addToBackStack("list");
f.commit();
...
}
...
這樣其實(shí)是不能實(shí)現(xiàn)該效果的。因?yàn)橹皇菍⒌谝粚拥腇ragmentTransaction管理的Fragment都加入了回退棧。同時(shí)因?yàn)檎{(diào)用replace,當(dāng)我們點(diǎn)擊button2,會(huì)看到第一層fragment不見了。這時(shí)候雖然fragmentTransaction管理的fragment沒有被銷毀但是視圖其實(shí)都已經(jīng)移除了。同時(shí)我們點(diǎn)擊button1他其實(shí)是將fragmentTransaction移除掉,而不是f。所以我們正確的實(shí)現(xiàn)是將f加到回退棧。
f.addToBackStack(null);
這樣后,會(huì)把第一層的fragment都去掉,然后添加第二層。點(diǎn)擊button1調(diào)用popBackStack后,第一層又會(huì)回來(replace相當(dāng)于remove和add的集合)。加入回退棧同時(shí)使用replace后,雖然第一層的實(shí)例沒有銷毀,但是視圖已經(jīng)是銷毀了。如果還想保存第一層的視圖,則把replace換成add。
如果對Fragment的一些基本概念還不是很了解,請看這篇文章 當(dāng)我們談Fragment時(shí),我們談些什么之一,這篇文章也不錯(cuò)Android -- Fragment 基本用法、生命周期與細(xì)節(jié)注意,也可以參考簡析 addToBackStack使用和Fragment執(zhí)行流程