Fragment篇——FragmentManager分析及用例
来源:互联网 发布:中山大学软件学院 编辑:程序博客网 时间:2024/04/30 00:04
说到管理Activity中的Fragment,自然就要重点说一下FragmentManager,之前已经说过了,getFragmentManager()获取到的FragmentManager支持原生的Fragment,而getSupportFragmentManager()支持的是v4包的Fragment。
获取Fragment的方法
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/fragment_study1" android:name="com.example.study.StudyFragment" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <fragment android:id="@+id/fragment_study2" android:name="com.example.study.StudyFragment" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <fragment android:tag="fragment_second" android:name="com.example.study.SecondFragment" android:layout_width="wrap_content" android:layout_height="wrap_content"/></LinearLayout>
获取Fragment的三种方式
fragmentManager = getSupportFragmentManager();// 通过id查找对应的Fragment实例fragment1 = (StudyFragment) fragmentManager.findFragmentById(R.id.fragment_study1);// 通过tag找到对应的Fragment,在动态加载和静态加载中都可以使用 secondFragment = (SecondFragment) fragmentManager.findFragmentByTag("fragment_second");// 获取添加到FragmentManager的所有Fragment,通过index访问,0代表最早添加的FragmentfragmentManager.getFragments()
FragmentManager是如何管理Fragment的
每次我们对Fragment的操作都需要通过FragmentTransaction,到了这里估计很多博客都已经说到了FragmentTransaction里面的几个操作方法,虽然在下也是要说的,顺便说一下Fragment管理的设计吧,不看不知道,看了才知道可牛逼哄哄了。
我们知道,没有FragmenActivity就没有Fragment。
那么为什么我们必须要继承自FragmentActivity呢,这就是Fragment设计上的便利了,开发者希望我们在使用Fragment的时候只需要关注对Fragment的操作,而Fragment的管理则交由FragmentActivity的FragmentManager来实现。
在FragmentAactivity这个类下面,当我们调用getSupportManager的时候
public class FragmentActivity extends BaseFragmentActivityJB implements ActivityCompat.OnRequestPermissionsResultCallback, ActivityCompatApi23.RequestPermissionsRequestCodeValidator { ···final FragmentController mFragments = FragmentController.createController(new HostCallbacks()); ··· public FragmentManager getSupportFragmentManager() { return mFragments.getSupportFragmentManager(); } ···}
我们可以看到FragmentActivity里面有一个FragmentController,这个FragmentController定义了所有对Fragment的管理操作,包括我们的Activity在onCreate,onResume,onDestroy等各种生命周期或回调对Fragment的影响,都是由这个类来控制的。
public class FragmentController { private final FragmentHostCallback<?> mHost; /** * Returns a {@link FragmentController}. */ public static final FragmentController createController(FragmentHostCallback<?> callbacks) { return new FragmentController(callbacks); } /** * Returns a {@link FragmentManager} for this controller. */ public FragmentManager getSupportFragmentManager() { //获取到FragmentManager对象 return mHost.getFragmentManagerImpl(); }
FragmentHostCallback是一个抽象类,负责调用各种各样的回调,这样的话,当Avtivity的状态,生命周期发生改变的时候,就可以通过这个回调接口进行统一管理,在上面提到的HostCallbacks是FragmentActivity里面的一个继承FragmentHostCallback的内部类。下面我们来看看FragmentHostCallback的默认实现
public abstract class FragmentHostCallback<E> extends FragmentContainer { private final Activity mActivity; ··· // 实例化FragmentManager对象,FragmentManagerImpl是继承自FragmentManager抽象类的,对FragmentManager的各种方法提供具体实现 final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl(); ···}
FragmentManagerImpl里面的具体实现就是有关Fragment是如何运行的,各种各样的生命周期,判断Fragment的不同状态,切换状态,Transaction只是用作记录对Fragment的操作记录,最终调用commit的时候,实际上调用的还是FragmentManagerImpl的方法
// FragmentManager 的实现类final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory { ··· @Override public FragmentTransaction beginTransaction() { // 每次的FragmentTransaction都是独立的 return new BackStackRecord(this); } ···}// Transaction的实现类final class BackStackRecord extends FragmentTransaction implements FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator { // 初始化的时候传入FragmentManagerImpl 的实例 public BackStackRecord(FragmentManagerImpl manager) { mManager = manager; } @Override public int commit() { //返回栈id,要是不添加进栈,返回-1 return commitInternal(false); } int commitInternal(boolean allowStateLoss) { // 提交以后无法再次提交 if (mCommitted) throw new IllegalStateException("commit already called"); if (FragmentManagerImpl.DEBUG) { Log.v(TAG, "Commit: " + this); LogWriter logw = new LogWriter(TAG); PrintWriter pw = new PrintWriter(logw); dump(" ", null, pw, null); } mCommitted = true; //是否要添加到回退栈 if (mAddToBackStack) { // 在回退栈中分配栈ID mIndex = mManager.allocBackStackIndex(this); } else { mIndex = -1; } //执行这个Transaction mManager.enqueueAction(this, allowStateLoss); return mIndex; }}
FragmentManagerImpl的部分实现
/** * 添加一个操作到待操作队列中 * * @param action 添加的操作 * @param allowStateLoss 是否允许丢失状态信息 * @throws 如果Activity已经销毁了抛出IllegalStateException异常 */ public void enqueueAction(OpGenerator action, boolean allowStateLoss) { if (!allowStateLoss) { // 检查状态是否丢失,默认的commit实现会执行这一步 checkStateLoss(); } synchronized (this) { if (mDestroyed || mHost == null) { throw new IllegalStateException("Activity has been destroyed"); } if (mPendingActions == null) { mPendingActions = new ArrayList<>(); } // 添加到待操作队列中 mPendingActions.add(action); scheduleCommit(); //执行Commit操作 } } private void scheduleCommit() { synchronized (this) { // 是否有延时的事务 boolean postponeReady = mPostponedTransactions != null && !mPostponedTransactions.isEmpty(); // 是否有待执行的事务 boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1; if (postponeReady || pendingReady) { mHost.getHandler().removeCallbacks(mExecCommit); // 执行这个Runnable mHost.getHandler().post(mExecCommit); } } } //通过handler调用,在主线程运行 public boolean execPendingActions() { //收集和执行延时的操作,这种延时是因为还没准备好?? ensureExecReady(true); boolean didSomething = false; //根据事务对象生成待执行的操作,这个事务对象是FragmentTransaction的实现 while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) { mExecutingActions = true; try { //优化执行事务,里面的处理逻辑相当复杂 optimizeAndExecuteOps(mTmpRecords, mTmpIsPop); } finally { //清空缓存事务队列 cleanupExec(); } didSomething = true; } //判断FragmentList是否需要延时,进而调用moveToState修改Fragment的状态,根据状态来触发Fragment的不同生命周期 doPendingDeferredStart(); return didSomething; }
上面的就是我们通过getSupportFragmentManager()获取到FragmentManager,然后再开启事务,提交事务所经历的代码流程。控制Fragment的生命周期的回调,通过FragmentManager的moveToState方法。
void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive)
关于Fragment的生命周期,要改篇再学习。现在继续来学习一下FragmentTransaction的一些常用方法
#将一个fragment实例添加到Activity里面指定id的容器中add(Fragment fragment, String tag)add(int containerViewId, Fragment fragment)add(int containerViewId, Fragment fragment, String tag); #将一个fragment实例从FragmentManager的FragmentList中移除remove(Fragment fragment);#只控制Fragment的隐藏hide(Fragment fragment)#只控制Fragment的显示show(Fragment fragment)#清除视图,从containerid指定的Added列表移除,FragmentList依然保留detach(Fragment fragment)#创建视图,添加到containerid指定的Added列表,FragmentList依然保留attach(Fragment fragment)#替换containerViewId中的fragment,它会把containerViewId中所有fragment删除,然后添加当前的fragmentreplace(int containerViewId, Fragment fragment)replace(int containerViewId, Fragment fragment, String tag)
FragmentTransaction的用例
之前的例子都已经对FragmentTransaction的用法有过一些介绍了
//添加Fragment到FragmentList中private void addFragment(Fragment fragment, String tag){ FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.add(R.id.fragment_container,fragment,tag); transaction.commit(); }// 清空fragmentList的所有Fragment,替换成新的Fragment,注意Fragment里面的坑private void replaceFragment(Fragment fragment, String tag){ FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.replace(R.id.fragment_container,fragment,tag); transaction.commit(); }//移除指定的Fragmentprivate void removeFragment(Fragment fragment){ FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.remove(fragment); transaction.commit(); }//把Fragment设置成显示状态,但是并没有添加到FragmentList中private void showFragment(Fragment fragment){ FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.show(fragment); transaction.commit(); }//把Fragment设置成显示状态,但是并没有添加到FragmentList中private void hideFragment(Fragment fragment){ FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.hide(fragment); transaction.commit(); }// 效果和show相近,创建视图,添加到containerid指定的Added列表,FragmentList依然保留,但是会引起生命周期的变化private void attachFragment(Fragment fragment){ FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.attach(fragment); transaction.commit(); }// 效果和hide相近,清除视图,从containerid指定的Added列表移除,FragmentList依然保留,但是会引起生命周期的变化private void detachFragment(Fragment fragment){ FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.detach(fragment); transaction.commit(); }
虽然新的Android版本中,Fragment在replace的时候不再重新实例化了(据说在旧的版本会出现这个问题,目前我使用的API 25 ),但是我们还是建议采用show/hide的方式来控制Fragment的显示和隐藏。还有一点需要注意的是,attach和detach会改变Fragment在Added列表中的顺序,从而也会改变Fragment显示的顺序。
FragmentTransaction的事务回退栈
上面介绍了常用的用法,接下来要介绍的是FragmentTransaction的事务回滚,FragmentTransaction把事务添加到回退栈中,只需要在调用 transaction.commit()之前,调用以下代码
//tag标记这个用于标记这个事务transaction.addToBackStack(String tag);
加入回退栈的时候,调用commit方法会返回一个index,作为事务的id,否则返回-1。使用popBackStack方法进行回退,弹出回退栈。
//默认将最上层的操作弹出回退栈popBackStack()//使用commit返回的事务idpopBackStack(int id, int flags); //使用加入回退栈时的tag值popBackStack(String name, int flags);
flag的取值,当取值0时,表示除了指定这一层之上的所有层都退出栈,指定的这一层为栈顶层;当取值POP_BACK_STACK_INCLUSIVE时,表示连着指定的这一层一起退出栈;
需要注意的是,使用popBackStack()来弹出栈内容的话,调用该方法后会将事物操作插入到FragmentManager的操作队列,只有当轮询到该事物时才能执行。如果想立即执行事物的话,需要使用下面几个对应的方法:
popBackStackImmediate() popBackStackImmediate(String tag) popBackStackImmediate(String tag, int flag) popBackStackImmediate(int id, int flag)
在FragmentActivity的onBackPressed()方法内可以看到,当popBackStackImmediate返回true的情况,则不会执行Activity的onBackPressed()方法
@Override public void onBackPressed() { if (!mFragments.getSupportFragmentManager().popBackStackImmediate()) { super.onBackPressed(); } }
2、回退栈(back stack)状态改变监听
FragmentManager还为我们提供了监控回退栈状态改变的方法:
addOnBackStackChangedListener(listener);//添加监听器 removeOnBackStackChangedListener(listener);//移除监听器
通过添加监听器,就可以在回退栈内容改变时,及时收到通知;
(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的问题之一。
参考文章:
Fragment详解之四——管理Fragment(2)
- Fragment篇——FragmentManager分析及用例
- Fragment篇——FragmentManager分析及用例
- Fragment FragmentManager FragmentTransaction 详解
- Fragment FragmentManager FragmentTransaction 详解
- Fragment与FragmentManager
- Fragment如何获得FragmentManager
- Fragment,FragmentManager, FragmentTransaction详解
- 42 Android fragmentManager 获取fragment
- FragmentActivity、Fragment、FragmentPagerAdapter与FragmentManager
- 【Fragment】FragmentManager和FragmentTransaction使用
- Android Fragment 之获取FragmentManager
- FragmentManager源码简单分析
- FragmentManager分析(个人笔记)
- FragmentManager及FragmentTransaction浅析
- FragmentManager , FragmentActivity 和 Fragment、Activity的区别?
- "Traditional ViewPager", "FragmentManager & Fragment"的用法
- Android Tab实现之FragmentManager+Fragment
- Fragment,Activity,FragmentManager之间那点事
- PropertyDrawer 自定义属性绘图
- Android初识(1)
- c 程序设计语言 1-9
- TCP&UDP的区别
- java读取隐藏文件的问题
- Fragment篇——FragmentManager分析及用例
- Java static
- API总结
- 腾讯笔试:格林码+map
- Android资源优化之拥抱svg
- 赵本山 教你如何在实战项目中使用WCF
- hadoop的第一个程序WordCount
- Android中使用Java8 新增语言功能
- 动态规划 数字三角形