Fragment 第三步——管理Fragment
一、概述
1、FragmentManager
要管理activity中的fragments,你就需要使用FragmentManager。通过getFragmentManager()或getSupportFragmentManager()获得
常用的方法有:
- manager.findFragmentById(); //根据ID来找到对应的Fragment实例,主要用在静态添加fragment的布局中,因为静态添加的fragment才会有ID
- manager.findFragmentByTag();//根据TAG找到对应的Fragment实例,主要用于在动态添加的fragment中,根据TAG来找到fragment实例
- manager.getFragments();//获取所有被ADD进Activity中的Fragment
2、FragmentTransaction
一般用来对当前的Fragment进行管理,包括add,replace,remove;常用的针对Fragment的方法有:
- //将一个fragment实例添加到Activity的最上层
- add(int containerViewId, Fragment fragment, String tag);
- //将一个fragment实例从Activity的fragment队列中删除
- remove(Fragment fragment);
- //替换containerViewId中的fragment实例,注意,它首先把containerViewId中所有fragment删除,然后再add进去当前的fragment
- replace(int containerViewId, Fragment fragment);
二、add()、replace()、remove()使用方法示例
下面就通过例子来看看以上几个函数的使用方法吧。
效果图如下:
- 点击“ADD Fragment1”,在将Fragment1添加到Activity的container中;
- 点击“ADD Fragment2”,将Fragment2添加到Activity的container中;
- 点击“Remove Fragment2”,将Fragment2的实例从container中移除,移除之后,就显示出其下方的fragment1的视图出来了。
- 再点击”replace Fragment1”,将container中的视图移除,然后添加上fragment2的视图。
那现在我们从头开始构建这个工程:
1、新建两个fragment1.xml 和 fragment2.xml:
从效果图中也可以看出,这两个XML什么都没有,只是通过背景色和文字来区别当前是哪个Fragment的XML布局文件而已,他们的布局代码如下:
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#ff00f0"
- android:orientation="vertical" >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="This is fragment 1"
- android:textColor="#000000"
- android:textSize="25sp" />
- </LinearLayout>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#ffff00"
- android:orientation="vertical" >
- <TextView
- android:id="@+id/fragment2_tv"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="This is fragment 2"
- android:textColor="#000000"
- android:textSize="25sp" />
- </LinearLayout>
2、建立对应的Fragment类:Fragment1和Fragment2
Fragment1:
- import android.os.Bundle;
- import android.support.v4.app.Fragment;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- public class Fragment1 extends Fragment {
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.fragment1, container, false);
- }
- }
- import android.os.Bundle;
- import android.support.v4.app.Fragment;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- public class Fragment2 extends Fragment {
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.fragment2, container, false);
- }
- }
3、MainActivity的布局
从上面的的效果图中也可以看出大概的布局,首先是三个Button,最下方是一个FrameLayout布局,它是用来做为container动态盛装fragment的;它就像是一个占位符,你设置多大,它其中的fragment就最大能有多大。记住,fragment也是Activity中的一个普通控件而已,只不过它可以像Activity一样用于显示的同时还能用来盛装其它控件!作为fragment的容器,即可以用FrameLayout也可以用LinearLayout或者RelativeLayout,都是一样的。activity_main.xml的布局代码如下:
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <Button
- android:id="@+id/btn_add_frag1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="ADD Fragment1" />
- <Button
- android:id="@+id/btn_add_frag2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="ADD Fragment2" />
- <Button
- android:id="@+id/btn_remove_frag2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="Remove Fragment2" />
- <Button
- android:id="@+id/btn_repalce_frag1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="replace Fragment1" />
- <FrameLayout
- android:id="@+id/fragment_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
- </LinearLayout>
4、MainActivity的实现:
(1)首先,先写一个添加fragment到Activity中的函数:
- private void addFragment(Fragment fragment, String tag) {
- FragmentManager manager = getSupportFragmentManager();
- FragmentTransaction transaction = manager.beginTransaction();
- transaction.add(R.id.fragment_container, fragment, tag);
- transaction.commit();
- }
- 先是传进来两个参数,一个是要添加的fragment实例,另一个是一个TAG
- 至于FragmentManager、FragmentTransaction就没什么好讲的,这是这么个流程,要获取它们的实例就得调用这些函数。
- 然后是add(R.id.fragment_container, fragment, tag)函数:第一个参数是要将fragment盛装的container,即我们上面的FrameLayout!第三个参数是tag,当传进去这个TAG,它就会跟这个fragment关联起来,当我们通过findFragmentByTag()时,根据这个TAG就能找到这个Fragment实例。进而对它进行操作,比如,我们下面的remove();
- 在通过transaction对Fragment操作完以后,一定要记得调用transaction.commit(),这样才会将操作提交到系统中,这里的代码才会最终起作用。
有没有觉得这个流程挺像数据库的回滚操作!对,其实就是这样的,这里其实就是一个针对Fragment的回滚操作,首先通过beginTransaction()来定义回滚的开始,然后通过transaction对Fragment进行一系列操作(我们这里只是进行了ADD,其实可以做一串操作),等操作完了利用commit()提交。这里就先初步讲到这,下节会细讲有关transaction的回滚过程。
(2)添加Fragment1和Fragment2:
好了,上面我们写好了一个函数addFragment(Fragment fragment, String tag),下面我们就要通过这个函数来添加Fragment1和Fragment2的实例了。
当点击“ADD Fragment1”按钮时:
- Fragment1 fragment1 = new Fragment1();
- addFragment(fragment1, "fragment1");
- Fragment2 fragment2 = new Fragment2();
- addFragment(fragment2, "fragment2");
(3)RemoveFragment2:
下面就是当点击“RemoveFragment2”按钮时的代码操作了:
- private void removeFragment2() {
- FragmentManager manager = getSupportFragmentManager();
- Fragment fragment = manager.findFragmentByTag("fragment2");
- FragmentTransaction transaction = manager.beginTransaction();
- transaction.remove(fragment);
- transaction.commit();
- }
- Fragment fragment = manager.findFragmentByTag("fragment2");
(4)ReplaceFragment1:
最后一个操作:ReplaceFragment1:
咱们先回到上面的RemoveFragment2操作,在RemoveFragment2之后,要知道我们的Activity的ADD队列中,就只有fragment1了。知道这一点之后,咱们看下面ReplaceFragment1的代码:
- private void replaceFragment1() {
- FragmentManager manager = getSupportFragmentManager();
- Fragment2 fragment2 = new Fragment2();
- FragmentTransaction transaction = manager.beginTransaction();
- transaction.replace(R.id.fragment_container, fragment2);
- transaction.commit();
- }
- transaction.replace(R.id.fragment_container, fragment2);
从上面的的讲解,大家可能也已经觉查到FragmentTransaction的Add()操作是维持着一个队列的,在这个队列中,根据ADD进去的先后顺序形成了一个链表,我们上面的操作在这个列表中的形式变化如下图所示:
源码在文章最底部给出
到这里add,replace,remove的使用方法就讲完了,但这里有个问题,必须根大家讲一下:我们上面说过replace操作会把container中的所有fragment全部删除,然后再将指定的fragment添加进去!但Android在实现时出现了BUG!在replace()时,并不能把以前所有Fragment清空,就因为这个系统工程产了BUG就会导致add()和Replace()不能共用!关于add()和Replace()不能共用的问题,我们会在下篇再讲。下面先给大家说说有关回滚的问题。
三、有关回滚——FragmentTransaction
1、FragmentTransaction事务回滚使用方法:
上部分,我们讲了有关添加、删除Fragment的操作,想将上一次commit的操作返回时,要怎么做呢。这就需要FragmentTransaction的回滚功能了。要使用回滚功能,只需要要使用下面两个代码:
在transaction.commit()之前,使用addToBackStack()将其添加到回退栈中。
- transaction.addToBackStack(String tag);
- manager.popBackStack();
当栈中有多层时,我们可以根据id或TAG标识来指定弹出到的操作所在层。函数如下:
- void popBackStack(int id, int flags);
- void popBackStack(String name, int flags);
- 参数int id是当提交变更时transaction.commit()的返回值。
- 参数string name是transaction.addToBackStack(String tag)中的tag值;
- 至于int flags有两个取值:0或FragmentManager.POP_BACK_STACK_INCLUSIVE;
- 当取值0时,表示除了参数一指定这一层之上的所有层都退出栈,指定的这一层为栈顶层;
- 当取值POP_BACK_STACK_INCLUSIVE时,表示连着参数一指定的这一层一起退出栈;
- 除了这几个函数,还有下面几个函数:有关他们的使用,我们在这小部分结尾时会提到
- popBackStackImmediate()
- popBackStackImmediate(String tag)
- popBackStackImmediate(String tag, int flag)
- popBackStackImmediate(int id, int flag)
先看下效果图:
1、逐个将Fragment1,2,3,4添加到窗口中,在添加时,每添加一个Fragment要利用transaction的addToBackStack将此次操作加入到回退栈中。
2、然后点击"PopBackStack"方法,将栈顶最上层的操作回退。退将最后一次添加回退出来,显示Fragment3.
3、点击“ADD Fragment4”将栈还原到1,2,3,4依次ADD进栈的状态,即操作1完成后的栈状态,然后点击“BackToStack2_0”,其实调用的方法是:
- manager.popBackStack("fragment2",0);//方法一,通过TAG回退
4、最后仍然是先点击"Add Fragment3"和"ADD Fragment4",将栈还原到操作1完成后的栈状态。然后点击“BackToStack2_INCLUSIVE”;其调用的方法是:
- manager.popBackStack("fragment2",FragmentManager.POP_BACK_STACK_INCLUSIVE);//方法一,通过TAG回退
下面我们看看具体实现:
(1)、首先,与上部分一样,先添加四个Fragment,并用背景色和文字来区分。这部分代码我们就不讲了。
主要看看点击按钮的代码处理方法。
(2)、首先是添加Fragment1:
- Fragment1 fragment1 = new Fragment1();
- stackID1 = addFragment(fragment1,"fragment1");
- private int stackID1,stackID2,stackID3,stackID4;
- private int addFragment(Fragment fragment,String stackName){
- FragmentManager manager = getSupportFragmentManager();
- FragmentTransaction transaction = manager.beginTransaction();
- transaction.add(R.id.fragment_container,fragment);
- transaction.addToBackStack(stackName);
- return transaction.commit();
- }
然后在每次ADD操作后,利用addToBackStack(string name)将每次ADD操作添加进回退栈中;
同样,添加Fragment2的代码如下,添加Fragment3,Fragment4的方法同理
- Fragment2 fragment2 = new Fragment2();
- stackID2 = addFragment(fragment2,"fragment2");
- private void popBackStack(){
- FragmentManager manager = getSupportFragmentManager();
- manager.popBackStack();
- }
- private void popBackStackToFrag2_0(){
- FragmentManager manager = getSupportFragmentManager();
- manager.popBackStack("fragment2",0);//方法一,通过TAG回退
- // manager.popBackStack(stackID2,0);//方法二,通过Transaction ID回退
- }
- private void popBackStackToFrag2_Inclusive(){
- FragmentManager manager = getSupportFragmentManager();
- manager.popBackStack("fragment2",FragmentManager.POP_BACK_STACK_INCLUSIVE);//方法一,通过TAG回退
- // manager.popBackStack(stackID2,FragmentManager.POP_BACK_STACK_INCLUSIVE);//方法二,通过Transaction ID回退
- }
使用popBackStack()来弹出栈内容的话,调用该方法后会将事物操作插入到FragmentManager的操作队列,只有当轮询到该事物时才能执行。如果想立即执行事物的话,需要使用下面几个对应的方法:
- popBackStackImmediate()
- popBackStackImmediate(String tag)
- popBackStackImmediate(String tag, int flag)
- popBackStackImmediate(int id, int flag)
2、回退栈(back stack)状态改变监听
FragmentManager还为我们提供了监控回退栈状态改变的方法:
- FragmentManager::addOnBackStackChangedListener(listener);//添加监听器
- FragmentManager::removeOnBackStackChangedListener(listener);//移除监听器
我们在上面代码的基础上,在MainAcitivy中为FragmentManager添加一个监听器,当回退栈状态改变时,打出一个LOG。具体实现如下:
(1)、OnCreate()中:
为fragmentManger添加一个监听器:
- FragmentManager manager = getSupportFragmentManager();
- listener = new FragmentManager.OnBackStackChangedListener() {
- @Override
- public void onBackStackChanged() {
- // TODO Auto-generated method stub
- Log.d("qijian","backstack changed");
- }
- };
- manager.addOnBackStackChangedListener(listener);
- protected void onDestroy() {
- // TODO Auto-generated method stub
- super.onDestroy();
- FragmentManager manager = getSupportFragmentManager();
- manager.removeOnBackStackChangedListener(listener);
- }
大家一定要注意,不管是这里的回退栈的监听还是其它的监听器,在页面对应的销毁时,都要记得remove掉,不然会造成页面不释放,这也是造成OOM的问题之一。
这样当回退栈内容出现变动时,变会打LOG出来,如图:
3、Transaction事务回退的原则
这里我们着重讲一下,回退是以commit()提交的一次事务为单位的,而不是以其中的add,replace等等操作为单位回退的,即,如果我们在一次提交是添加了fragment2,fragment3,fragment4,那么回退时,会依据添加时的顺序,将它们一个个删除,返回到没有添加fragment4,fragment3,fragment2的状态。
下面我们仍然写一个例子来讲明一下事务的回退原则,效果图如下:
- 1、首先,添加Fragment1,提交一次事务
- 2、然后,一次添加Fragment2,Fragment3,Fragment4,然后提交一次事务
- 3、利用popBackStack()将顶层事务出栈,可以看到把Fragment2,Fragment3,Fragment4一次出栈,界面显示在了Fragment1的位置,这就充分说明了,回滚是以提交的事务为单位进行的!
下面是代码实现部分:
1、同样,新建四个Fragment,分别利用背景色和文字来表明之间的不同。
2、然后添加Fragment1的代码如下:
- private void addFragment1() {
- Fragment1 fragment1 = new Fragment1();
- FragmentManager manager = getSupportFragmentManager();
- FragmentTransaction transaction = manager.beginTransaction();
- transaction.add(R.id.fragment_container, fragment1);
- transaction.addToBackStack("fragment1");
- transaction.commit();
- }
- private void addOtherFragments() {
- Fragment2 fragment2 = new Fragment2();
- Fragment3 fragment3 = new Fragment3();
- Fragment4 fragment4 = new Fragment4();
- FragmentManager manager = getSupportFragmentManager();
- FragmentTransaction transaction = manager.beginTransaction();
- transaction.add(R.id.fragment_container, fragment2);
- transaction.add(R.id.fragment_container, fragment3);
- transaction.add(R.id.fragment_container, fragment4);
- transaction.addToBackStack("other fragments");
- transaction.commit();
- }
4、点击popBackStack按钮时的代码
- private void popBackStack() {
- FragmentManager manager = getSupportFragmentManager();
- manager.popBackStack();
- }
一、hide()、show()
1、基本使用
这两个函数的功能非常简单,
- public FragmentTransaction hide(Fragment fragment);//将指定的fragment隐藏不显示
- public FragmentTransaction show(Fragment fragment);//将以前hide()过的fragment显示出来
- 首先,依次添加fragment1,fragment2,fragment3
- 然后点击”frag3 hide”,将fragment3隐藏不显示,所以就显示出来它的下一层fragment2的视图
- 然后再点击“frag3 show”,将fragment3重新显示出来
- 然后点击“frag2 hide”按钮,将fragment2隐藏,但是由于fragment3覆盖在fragment2之上,fragment2隐藏之后对fragment3没有任何影响,所以在视图上看不到任何效果。
- 这时候,我们再点击“hide frag3”,将fragment3隐藏起来,这时候,由于fragment3和fragment2都隐藏了,所以显示的就是fragment1的视图。
- 最后,点击“frag2 show”将fragment2显示出来
代码如下:
(1)、同样是新建三个fragment,命名为Fragment1,Fragment2,Fragment3,同样是用背景色和文字来区别;
(2)、然后是点击“add frag1”按钮的代码
- Fragment1 fragment1 = new Fragment1();
- addFragment(fragment1, "fragment1");
- private void addFragment(Fragment fragment, String tag) {
- FragmentManager manager = getSupportFragmentManager();
- FragmentTransaction transaction = manager.beginTransaction();
- transaction.add(R.id.fragment_container,fragment, tag);
- transaction.addToBackStack(tag);
- transaction.commit();
- }
(3)、frag3 hide的代码:
- FragmentManager manager = getSupportFragmentManager();
- Fragment fragment = manager.findFragmentByTag("fragment3");
- FragmentTransaction transaction = manager.beginTransaction();
- transaction.hide(fragment);
- transaction.addToBackStack("hide fragment3");
- transaction.commit();
(4)、frag3 show的代码:
- FragmentManager manager = getSupportFragmentManager();
- Fragment fragment = manager.findFragmentByTag("fragment3");
- FragmentTransaction transaction = manager.beginTransaction();
- transaction.show(fragment);
- transaction.addToBackStack("show fragment3");
- transaction.commit();
2、在实战中的运用方法
如果我们使用replace来切换页面,那么在每次切换的时候,Fragment都会重新实例化,重新加载一边数据,这样非常消耗性能和用户的数据流量。
这是因为replace操作,每次都会把container中的现有的fragment实例清空,然后再把指定的fragment添加进去,就就造成了在切换到以前的fragment时,就会重新实例会fragment。
正确的切换方式是add(),切换时hide(),add()另一个Fragment;再次切换时,只需hide()当前,show()另一个。
这样就能做到多个Fragment切换不重新实例化:(基本算法如下)
- public void switchContent(Fragment from, Fragment to) {
- if (!to.isAdded()) { // 先判断是否被add过
- transaction.hide(from).add(R.id.content_frame, to).commit(); // 隐藏当前的fragment,add下一个到Activity中
- } else {
- transaction.hide(from).show(to).commit(); // 隐藏当前的fragment,显示下一个
- }
- }
二、detach()、attach()
这两个函数的声明如下:
- public FragmentTransaction detach(Fragment fragment);
- public abstract FragmentTransaction attach(Fragment fragment);
attach():显然这个方法与detach()所做的工作相反,它一方面利用fragment的onCreateView()来重建视图,一方面将此fragment添加到ADD队列中;这里最值得注意的地方在这里:由于是将fragment添加到ADD队列,所以只能添加到列队头部,所以attach()操作的结果是,最新操作的页面始终显示在最前面!这也就解释了下面的例子中,为了fragment2 detach()后,当再次attach()后,却跑到了fragment3的前面的原因。还有,由于这里会将fragment添加到Activity的ADD队列中,所以在这里调用fragment::isAdded()将返回True;
下面用一个例子来讲讲,有关这上面所讲解的知识,效果图如下:
- (1)、同样,先依次添加Fragment1,Fragment2,Fragment3
- (2)、然后点击“frag3 detach”,将fragment3的View视图删除,然后从ADD队列中将fragment移除。之后点击“fragment is added?”根据TOAST可以看出,fragment::isAdded()函数返回值是false;
- (3)、然后点击“frag3 attach”,将fragment重新与Activity绑定,它有两个动作,一方面重建fragment视图,一方面将fragment添加到Activity的ADD队列中;所以这时候点击“fragment is added?”,fragment::isAdded()函数返回值是true;
- (4)、然后点击“frag2 detach”,由于fragment2在fragment3之下,所以给fragment2使用detach,在界面上看不出任何效果。
- (5)、但当点击“frag2 attach”时,问题出现了,由于attach()会做两件事,一方面重建fragment视图,一方面将fragment添加到Activity的ADD队列中;由于是ADD队列,所以肯定添加的位置肯定在队首;所以fragment2就显示在了最上方,把fragment3盖住了,这就是为什么在点击“frag2 attach”之后,却可以看到fragment2的视图的原因!
1、点击frag3 detach按钮的代码
- FragmentManager manager = getSupportFragmentManager();
- Fragment fragment = manager.findFragmentByTag("fragment3");
- FragmentTransaction transaction = manager.beginTransaction();
- transaction.detach(fragment);
- transaction.addToBackStack("detach fragment3");
- transaction.commit();
2、点击“frag3 attach”按钮的代码
- FragmentManager manager = getSupportFragmentManager();
- Fragment fragment = manager.findFragmentByTag("fragment3");
- FragmentTransaction transaction = manager.beginTransaction();
- transaction.attach(fragment);
- transaction.addToBackStack("attach fragment3");
- transaction.commit();
好了,到这里,有关Fragment的操作都已经讲完了,下面就讲讲有关在Fragment操作中Android的BUG!
三、系统BUG——add()和replace()千万不要共用!!!
先写个例子来看一下问题:
这个例子分为两部分,
- 第一部分:先利用add()函数,依次add进去fragment1,fragment2,fragment3,fragment4,fragment5,然后利用"print back stack"打印出当前在回退栈中每次操作的名称;每回退一次打一次回退栈内容,可见一切都是正常的,即回退栈顶的项,正是当前VIEW顶部显示的内容。
- 第二部分,如果我们先利用add()函数,依次add进去fragment1,fragment2,fragment3,fragment4,然后再利用replace函数添加进去fragment5;然后利用"print back stack"打印出当前在回退栈中每次操作的名称;可以看到,当回退栈顶是"add fragment4"时,fragment4却没有出现,点击返回按钮,却把这个"add fragment4"的Transaction操作给返回了。同样的现象也发生在fragment2中;
还是先看看实现代码:
1、添加fragment,比如添加fragment1,其它fragment2,fragment3,fragment4同理
- Fragment1 fragment1 = new Fragment1();
- addFragment(fragment1, "add fragment1");
- private void addFragment(Fragment fragment, String tag) {
- FragmentManager manager = getSupportFragmentManager();
- FragmentTransaction transaction = manager.beginTransaction();
- transaction.add(R.id.fragment_container, fragment);
- transaction.addToBackStack(tag);
- transaction.commit();
- }
代码上没什么难度,在添加到回退栈时,添加TAG:"replace fragment5"
- Fragment5 fragment5 = new Fragment5();
- FragmentManager manager = getSupportFragmentManager();
- FragmentTransaction transaction = manager.beginTransaction();
- transaction.replace(R.id.fragment_container, fragment5);
- transaction.addToBackStack("replace fragment5");
- transaction.commit();
这里要讲一个函数了:
- public int getBackStackEntryCount();//获取回退栈中,Transaction回退操作的数量
- public BackStackEntry getBackStackEntryAt(int index);//根据索引得到回退栈变量
- TextView tv = (TextView) findViewById(R.id.tv_stack_val);
- FragmentManager manager = getSupportFragmentManager();
- int count = manager.getBackStackEntryCount();
- StringBuilder builder = new StringBuilder("回退栈内容为:\n");
- for (int i = --count;i>=0;i--){
- FragmentManager.BackStackEntry entry= manager.getBackStackEntryAt(i);
- builder.append(entry.getName()+"\n");
- }
- tv.setText(builder.toString());
问题出在了replace()操作上,replace()操作原意的实现应该是清空container中所有的fragment实例,然后再将指定的fragment添加到container的ADD队列中;但在清空时,他们的代码是这样写的:
- for (int i=0;i<mManager.mAdded.size(); i++) {
- Fragment old = mManager.mAdded.get(i);
- ……
- mManager.removeFragment(old, mTransition, mTransitionStyle);
- }
首先,先逐个得到mAdded队列中的fragment,即:
- Fragment old = mManager.mAdded.get(i);
- mManager.removeFragment(old, mTransition, mTransitionStyle);
比如,我们上面的,在mAdded队列中有1,2,3,4,5这五个fragment;
首先,当i=0时,移除1,这没错!但它是将mAdded队列中的1直接移除的哦!所以移除1以后,mAdded队列的值变成了2,3,4,5
这时候,当i=1时,删除的是3!!!!知道问题所在了吧!所以在删除3后,mAdded队列的值为2,4,5
所以当i=2时,删除的是5!!!!所以这就造成了为什么我们的fragment2和fragment4明明在回退栈中,即显示不出来的原因,因为他们在删除时根本就没有删除,而在回退栈回退时却又要跟着操作顺序来回退,即remove fragment5,逐个add进去fragment4,fragment3,fragment2,fragment1,而又由于fragment4和fragment2没有被删除,所以出现了错误,导致系统哪里出了问题,所以显示不出来,至于是哪里出了问题,我也不知道,因为我尝试了show()和attach() fragment4都还是没有效果。可能是系统底层的问题吧。所以,这里忠告大家,add()和replace()不能共用!!!!!