前言:follow your heart,be your own kinghtml
相关文章:java
一、《Fragment详解之一——概述》
二、《Fragment详解之二——基本使用方法》
三、《Fragment详解之三——管理Fragment(1)》
四、《Fragment详解之四——管理Fragment(2)》
五、《Fragment详解之五——Fragment间参数传递》
六、《Fragment详解之六——如何监听fragment中的回退事件与怎样保存fragment状态》android
前面给你们稍微看了要怎么使用fragment,在上篇中,咱们也初步接触到了add,replace这些fragment操做的函数,下面就再详细讲讲如何管理Fragment页面吧。数据库
要管理activity中的fragments,你就须要使用FragmentManager。经过getFragmentManager()或getSupportFragmentManager()得到
经常使用的方法有:app
manager.findFragmentById(); //根据ID来找到对应的Fragment实例,主要用在静态添加fragment的布局中,由于静态添加的fragment才会有ID manager.findFragmentByTag();//根据TAG找到对应的Fragment实例,主要用于在动态添加的fragment中,根据TAG来找到fragment实例 manager.getFragments();//获取全部被ADD进Activity中的Fragment
通常用来对当前的Fragment进行管理,包括add,replace,remove;
经常使用的针对Fragment的方法有:ide
//将一个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);
还有hide()、show()、detach()、attach()这些函数,咱们下篇再讲,这节先对Fragment的用法有一个初步了解;函数
下面就经过例子来看看以上几个函数的使用方法吧。
效果图以下:布局
那如今咱们从头开始构建这个工程:spa
从效果图中也能够看出,这两个XML什么都没有,只是经过背景色和文字来区别当前是哪一个Fragment的XML布局文件而已,他们的布局代码以下:.net
fragment1.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>
fragment2.xml:
<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>
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); } }
与上一篇同样,也只是在onCreateView()时返回对应的布局。一样,Fragment2的定义以下:
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); } }
从上面的的效果图中也能够看出大概的布局,首先是三个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>
(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的回滚操做,首先经过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");
当点击“ADD Fragment2”按钮时:
Fragment2 fragment2 = new Fragment2(); addFragment(fragment2, "fragment2");
这里须要注意的是,当咱们添加每一个Fragment实例时,都传进去一个对应的TAG,fragment1对应的是“fragment1”,fragment2对应的是“fragment2”,经过这些TAG,咱们就能够经过findFragmentByTag()来获取它们了。
(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");
找到咱们当时ADD进Activity的fragment2实例,而后经过transaction.remove(fragment);将它删除;从效果图中能够看到,因为咱们移除了fragment2的实例,而又因为fragment2是在界面最上方的,因此把它删除了以后,天然就剩下了fragment1在最上方了,因此咱们就看到了fragment1的界面。那若是咱们移除的是fragment1呢?答案是界面没有任何变化!由于fragment1的实例是在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);
这里replace传进去的第一个参数是容器ID,第二个参数是要新增的fragment。既然要replace(),那它是针对哪一个fragment进行replace()呢?怎么没有指定要替换的fragment!为何这里的第一个参数是盛装Activity中全部Fragment的container的ID呢?没错,这里的replace操做会把这个cotainer中全部fragment清空!!!!而后再把fragment2添加进去!
从上面的的讲解,你们可能也已经觉查到FragmentTransaction的Add()操做是维持着一个队列的,在这个队列中,根据ADD进去的前后顺序造成了一个链表,咱们上面的操做在这个列表中的形式变化以下图所示:
源码在文章最底部给出
到这里add,replace,remove的使用方法就讲完了,但这里有个问题,必须根你们讲一下:咱们上面说过replace操做会把container中的全部fragment所有删除,而后再将指定的fragment添加进去!但Android在实现时出现了BUG!在replace()时,并不能把之前全部Fragment清空,就由于这个系统工程产了BUG就会致使add()和Replace()不能共用!关于add()和Replace()不能共用的问题,咱们会在下篇再讲。下面先给你们说说有关回滚的问题。
上部分,咱们讲了有关添加、删除Fragment的操做,想将上一次commit的操做返回时,要怎么作呢。这就须要FragmentTransaction的回滚功能了。
要使用回滚功能,只须要要使用下面两个代码:
在transaction.commit()以前,使用addToBackStack()将其添加到回退栈中。
transaction.addToBackStack(String tag);
在须要回退时,使用popBackStack()将最上层的操做弹出回退栈。
manager.popBackStack();
这里的popBackStack()是弹出默认的最上层的栈顶内容。
当栈中有多层时,咱们能够根据id或TAG标识来指定弹出到的操做所在层。函数以下:
void popBackStack(int id, int flags); void popBackStack(String name, int flags);
其中
popBackStackImmediate() popBackStackImmediate(String tag) popBackStackImmediate(String tag, int flag) popBackStackImmediate(int id, int flag)
下面咱们就经过一个例子来说解一下有关回退栈中的操做过程:
先看下效果图:
总体流程是这样的:
一、逐个将Fragment1,2,3,4添加到窗口中,在添加时,每添加一个Fragment要利用transaction的addToBackStack将这次操做加入到回退栈中。
二、而后点击"PopBackStack"方法,将栈顶最上层的操做回退。退将最后一次添加回退出来,显示Fragment3.
三、点击“ADD Fragment4”将栈还原到1,2,3,4依次ADD进栈的状态,即操做1完成后的栈状态,而后点击“BackToStack2_0”,其实调用的方法是:
manager.popBackStack("fragment2",0);//方法一,经过TAG回退
从这里能够看出,要回退到添加ADD Fragment2的状态,注意最后一个参数,这里设为0,代表,要回退ADD Fragment2的以后的操做,将ADD Fragment2的操做置为栈顶。从效果图中也能够看出,点击后的视图在Fragment2的位置
四、最后仍然是先点击"Add Fragment3"和"ADD Fragment4",将栈还原到操做1完成后的栈状态。而后点击“BackToStack2_INCLUSIVE”;其调用的方法是:
manager.popBackStack("fragment2",FragmentManager.POP_BACK_STACK_INCLUSIVE);//方法一,经过TAG回退
这里与上面的主要不一样点在于第二个参数,这里设置为POP_BACK_STACK_INCLUSIVE,即在出栈时连带ADD Fragment2的操做一块出栈,放在栈顶的是ADD Fragment1的操做,因此放在界面上就是显示的是Fragment1的视图。
下面咱们看看具体实现:
(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(); }
首先,这里的stackID1,stackID2,stackID3,stackID4是用来保存每次commit()后返回的Transaction的ID值。在void popBackStack(int id, int flags);时,其中的参数id就是这个值
而后在每次ADD操做后,利用addToBackStack(string name)将每次ADD操做添加进回退栈中;
一样,添加Fragment2的代码以下,添加Fragment3,Fragment4的方法同理
Fragment2 fragment2 = new Fragment2(); stackID2 = addFragment(fragment2,"fragment2");
(3)、而后是回退栈顶内容:
private void popBackStack(){ FragmentManager manager = getSupportFragmentManager(); manager.popBackStack(); }
(4)、接着是点击BackToFrag2_0按钮的内容,这里有两种方法实现,一种是指定TAG,一种是利用Commit()返回的ID
private void popBackStackToFrag2_0(){ FragmentManager manager = getSupportFragmentManager(); manager.popBackStack("fragment2",0);//方法一,经过TAG回退 // manager.popBackStack(stackID2,0);//方法二,经过Transaction ID回退 }
(5)、最后是点击BackToFrag2_INCLUSIVE按钮的代码:
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)
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);
(2)、当onDestory()中将监听器remove掉:
protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); FragmentManager manager = getSupportFragmentManager(); manager.removeOnBackStackChangedListener(listener); }
你们必定要注意,不论是这里的回退栈的监听仍是其它的监听器,在页面对应的销毁时,都要记得remove掉,否则会形成页面不释放,这也是形成OOM的问题之一。
这样当回退栈内容出现变更时,变会打LOG出来,如图:
源码在文章底部给出
这里咱们着重讲一下,回退是以commit()提交的一次事务为单位的,而不是以其中的add,replace等等操做为单位回退的,即,若是咱们在一次提交是添加了fragment2,fragment3,fragment4,那么回退时,会依据添加时的顺序,将它们一个个删除,返回到没有添加fragment4,fragment3,fragment2的状态。
下面咱们仍然写一个例子来说明一下事务的回退原则,效果图以下:
下面是代码实现部分:
一、一样,新建四个Fragment,分别利用背景色和文字来代表之间的不一样。
二、而后添加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(); }
三、而后是添加其它三个Fragment的代码以下:
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(); }
再一次重申,从代码中也能够看到,是依次将Fragment二、Fragment三、Fragment4加入容器以后,再提交一次事务,因此下面回滚时,会将他们反顺序的依次删除。即remove(fragment4)、remove(fragment3)、remove(fragment2)
四、点击popBackStack按钮时的代码
private void popBackStack() { FragmentManager manager = getSupportFragmentManager(); manager.popBackStack(); }
好了,到这里这篇文章就结束了,这篇文章太TM长了……你们估计看得也快要吐了……知识点太多,又想能给你们讲的浅显易懂就只有拉长篇幅了……
源码中有三个工程:
一、《harvicBlog3_1》:对应第二部分:add()、replace()、remove()使用方法示例
二、《harvicBlog3_2》:对应第三部分《有关回滚——FragmentTransaction》中的:FragmentTransaction事务回滚使用方法和回退栈内容监听部分
三、《harvicBlog3_3》:对应第三部分《有关回滚——FragmentTransaction》中的:Transaction事务回退的原则部分
若是本文有帮到你,记得加关注哦
源码下载地址:http://download.csdn.net/detail/harvic880925/8578519
请你们尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/44927375, 谢谢!