Fragment 操作原理

fragment 本质

fragment 本质上是 view 的容器和控制器,fragment 是 activity 的碎片。

activity 是什么呢?activity 是四大组件之一,因为 LMK(Low Memery Killer)机制,4 大组件是 android 系统的组成部件,4 大组件就是我们提供给用户的功能的载体,4 大组件还是我们提供给用户的功能的入口。Activity Service BroadcastReceiver ContentProvider,Activity 是带用户界面的这些功能的载体,Service 是不带用户界面的功能的载体。和 Service 比较,Activity 相当于 MVC 中的 View。但我们把 Activity 剖析开来理解,Activity 承担了 View 控件的容器和控制器功能。Activity 还承担了 View 控件的数据的容器的功能。

系统的四大组件是系统自动创建,调用

fragment 除了不是系统组件外,拥有其他所有 Activity 的功能。fragment 的存在就是对 activity 的功能进行拆分,降低 activity 的负担,减少 activity 中的代码量。

fragment 还有对 fragment 中的 view 的状态进行保持的能力,需要保持的 view 必须设置 id,否则不能保存 view 的状态。

FragmentTransaction 的 add、remove、replace、hide、show 操作

FragmentTransaction 的 add、remove、replace、hide、show 操作本质上是对 fragment 中的 view 树进行 add、remove、hide、show 操作

  • add 是把 fragment 中的 view 树添加到容器 viewgroup 中,相当于 viewgroup.addview();
  • remove 是把 fragment 中的 view 树对象从容器 viewgroup 中移除,相当于 viewgroup.removeView();
  • replace 是 add 操作和 remove 操作的合体,相当于先 remove 掉 viewgroup 容器中所有的 fragment,再添加新的 fragment 对象。replace 有个 bug,remove 的时候如果 viewgroup 容器中有多个 fragment,比如 1、2、3、4、5、6,只移除1、3、5这些序号为奇数的 fragment,这个 bug 是 v4 包中的 bug,到目前版本 level 23 仍然没有修复
  • hide 操作相当于设置 fragment 对应的 view 为 gone
  • show 操作相当于设置 fragment 对应的 view 为 visible

FragmentTransaction 的 addToBackStack 功能

addToBackStack 是把该事务所有操作构成的操作集合都添加到 FragmentManager 对象的后退任务栈中,作为任务栈中的一个元素,当我们按 back 键的时候进行该操作集合构成的元素进行的逆向操作,一次弹出一个元素,主动调用 FragmentManager.popBackStack 方法也可以进行一个弹栈操作。

Fragment 操作原理

fragment 的 add 操作到底是怎么实现的?通过查看源码,fragment 的 add 操作主要要做下面的事情: 
1. 通过 activity 获取到 FragmentManager 对象,这里会 new 一个 FragmentManagerImpl 对象 
2. 通过 FragmentManager 开启一个事务,这里会 new 一个 BackStackRecord 对象,一个 BackStackRecord 也就是一个事务 
3. 通过 FragmentTransaction 执行 add 操作,本质上是 new 了一个 Op 对象,添加到了 BackStackRecord 内部的队列中(BackStackRecord 有一个队列用来保存这次事务进行的所有操作) 
4. 通过 FragmentTransaction 执行 commit 方法,把 BackStackRecord 添加到 manager 的 Action 队列中 
5. 主线程中处理 Action 中的 BackStackRecord,调用 BackStackRecord 的 run 方法 
6. BackStackRecord 的 run 方法处理 BackStackRecord 内部的队列中的 Op 对象,如果是 add 类型 Op,调用 Manager 的 addFragment 
7. 把 fragment 对象添加到 manager 的 mAdded 集合中,修改 fragment 的状态,执行 fragment 的生命周期方法,把 fragment 中的 view 添加到 fragment 的容器 viewgroup 中

1. FragmentActivity.getSupportFragmentManager()

//FragmentActivity.java
final FragmentManagerImpl mFragments = new FragmentManagerImpl();

public FragmentManager getSupportFragmentManager() {
    return mFragments;
}

FragmentActivity 的 fragmentManager 就是 FragmentManagerImpl 对象

2. FragmentManager.beginTransaction()

//FragmentManagerImpl.java
@Override
public FragmentTransaction beginTransaction() {
    return new BackStackRecord(this);
}

开始事务就是创建一个 BackStackRecord 对象,该对象用来表示一个fragment事务

3. FragmentTransaction.add()

//BackStackRecord.java
public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
    doAddOp(containerViewId, fragment, tag, OP_ADD);
    return this;
}

private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
    fragment.mFragmentManager = mManager;

    if (tag != null) {
        ...
        fragment.mTag = tag;
    }

    if (containerViewId != 0) {
        ...
        fragment.mContainerId = fragment.mFragmentId = containerViewId;
    }

    //新建一个 Op,添加到队列中
    Op op = new Op();
    op.cmd = opcmd;
    op.fragment = fragment;
    addOp(op);
}

//添加 Op 到链表中
void addOp(Op op) {
    if (mHead == null) {
        mHead = mTail = op;
    } else {
        op.prev = mTail;
        mTail.next = op;
        mTail = op;
    }
    ...
    mNumOp++;
}

添加 Fragment 就是给 fragment 事务对象中Op对象链表中添加一个Op对象

4. FragmentTransaction.commit()

public int commit() {
    return commitInternal(false);
}

int commitInternal(boolean allowStateLoss) {
    ...
    //添加 transaction 到 manager 的队列中
    mManager.enqueueAction(this, allowStateLoss);
    return mIndex;
}

提交事务就是把事务对象添加到 FragmentManager 队列中

5. FragmentManagerImpl.enqueueAction()

public void enqueueAction(Runnable action, boolean allowStateLoss) {

    synchronized (this) {
        ...
        if (mPendingActions == null) {
            mPendingActions = new ArrayList<Runnable>();
        }
        mPendingActions.add(action);
        if (mPendingActions.size() == 1) {
            mActivity.mHandler.removeCallbacks(mExecCommit);
            mActivity.mHandler.post(mExecCommit);
        }
    }
}

Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
        execPendingActions();
}

/**
 * Only call from main thread!
 */
public boolean execPendingActions() {
    ...
    while (true) {
        int numActions;

        synchronized (this) {
            ...
            numActions = mPendingActions.size();
            if (mTmpActions == null || mTmpActions.length < numActions) {
                mTmpActions = new Runnable[numActions];
            }
            mPendingActions.toArray(mTmpActions);
            mPendingActions.clear();
            mActivity.mHandler.removeCallbacks(mExecCommit);
        }

        mExecutingActions = true;
        for (int i=0; i<numActions; i++) {
            //执行 pendding 中的 action.run,就是执行事务
            mTmpActions[i].run();
            mTmpActions[i] = null;
        }
        ...
    }

    ...
    return didSomething;
}

6. BackStackRecord.run()

public void run() {
    ...
    bumpBackStackNesting(1);

    Op op = mHead;
    while (op != null) {
        switch (op.cmd) {
            case OP_ADD: {
                Fragment f = op.fragment;
                f.mNextAnim = op.enterAnim;
                mManager.addFragment(f, false);
            } break;
            case OP_REPLACE: {
                Fragment f = op.fragment;
                if (mManager.mAdded != null) {
                    for (int i=0; i<mManager.mAdded.size(); i++) {
                        Fragment old = mManager.mAdded.get(i);
                        ...
                                mManager.removeFragment(old, mTransition, mTransitionStyle);
                            }
                        }
                    }
                }
                if (f != null) {
                    f.mNextAnim = op.enterAnim;
                    mManager.addFragment(f, false);
                }
            } break;
            case OP_REMOVE: {
                Fragment f = op.fragment;
                f.mNextAnim = op.exitAnim;
                mManager.removeFragment(f, mTransition, mTransitionStyle);
            } break;
            case OP_HIDE: {
                Fragment f = op.fragment;
                f.mNextAnim = op.exitAnim;
                mManager.hideFragment(f, mTransition, mTransitionStyle);
            } break;
            case OP_SHOW: {
                Fragment f = op.fragment;
                f.mNextAnim = op.enterAnim;
                mManager.showFragment(f, mTransition, mTransitionStyle);
            } break;
            case OP_DETACH: {
                Fragment f = op.fragment;
                f.mNextAnim = op.exitAnim;
                mManager.detachFragment(f, mTransition, mTransitionStyle);
            } break;
            case OP_ATTACH: {
                Fragment f = op.fragment;
                f.mNextAnim = op.enterAnim;
                mManager.attachFragment(f, mTransition, mTransitionStyle);
            } break;

        }

        op = op.next;
    }

    mManager.moveToState(mManager.mCurState, mTransition,
            mTransitionStyle, true);

    if (mAddToBackStack) {
        mManager.addBackStackState(this);
    }
}

调用 FragmentManager 中的 add、remove、show、hide 等方法,replace 方法是移除 mManager.mAdded 中的 fragment

7. FragmentManager.add()

public void addFragment(Fragment fragment, boolean moveToStateNow) {
    if (mAdded == null) {
        mAdded = new ArrayList<Fragment>();
    }
    if (DEBUG) Log.v(TAG, "add: " + fragment);
    makeActive(fragment);
    if (!fragment.mDetached) {
        if (mAdded.contains(fragment)) {
            throw new IllegalStateException("Fragment already added: " + fragment);
        }
        //添加到 mAddded 集合中
        mAdded.add(fragment);
        fragment.mAdded = true;
        fragment.mRemoving = false;
        if (fragment.mHasMenu && fragment.mMenuVisible) {
            mNeedMenuInvalidate = true;
        }
        if (moveToStateNow) {
            moveToState(fragment);
        }
    }
}

moveToState(fragment) 方法会触发 fragment 的生命周期方法

时间: 2024-08-25 19:11:54

Fragment 操作原理的相关文章

Android进阶——Fragment详解之操作原理(三)

引言 前一篇文章总结了Fragment 的基本概念和基本的用法,相信大家也能够掌握一些知识了,但是对于一些操作可能还是不知其所以然,说实话曾经很长一段时间为也是晕乎乎的,后来才慢慢重视去学习了解,才略知一二,遂分享之. 一.管理Fragement所涉及到的关键类 应用Fragment的过程中涉及到的关键类主要有:FragmentManager和.FragmentManagerImpl.FragmentTransaction和BackStackRecord等. 二.Fragment操作原理详述 1

Android 导航条效果实现(六) TabLayout+ViewPager+Fragment

TabLayout 一.继承结构 public class TabLayout extends HorizontalScrollView java.lang.Object ? android.view.View ? android.view.ViewGroup ? android.widget.FrameLayout ? android.widget.HorizontalScrollView ? android.support.design.widget.TabLayout 二.TabLayou

安卓性能优化之Activity和Fragment通过onSaveInstanceState()保存和恢复数据

Activity和Fragment 都有自己的生命周期,而且很类似.Fragment比Activity多了onAttach()和onCreateView()这些方法.整体它们两者是一样的周期,都会经历从创建视图( onCreate(),onCreateView(),onStart() )到暂停( onPause(), onStop() ) 到重新返回( onResume() ) 到最后销毁( onDetroyView(), onDestroy() ) 这些方法. 之前有提过,熟悉组件的这些生命周

fragment跳转

activity的布局代码: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match

FragmentTabHost切换Fragment避免重新加载Fragment,即重复调用Fragment的onCreateView

FragmentTabHost一切换再返回的时候Fragment就会调用onCreateView重新绘制页面,被这个问题坑了好久.刚开始也不知道是 FragmentTabHost还是Fragment的原因,网上找了好久也没找到解决办法.终于搜了好久还是找到了: 解决方法,在fragment onCreateView 里缓存View: private View rootView;// 缓存Fragment view @Override public View onCreateView(Layout

Fragment事务管理源码分析

概述 在Fragment使用中,有时候需要对Fragment进行add.remove.show.hide.replace等操作来进行Fragment的显示隐藏等管理,这些管理是通过FragmentTransaction进行事务管理的.事务管理是对于一系列操作进行管理,一个事务包含一个或多个操作命令,是逻辑管理的工作单元.一个事务开始于第一次执行操作语句,结束于Commit.通俗地将,就是把多个操作缓存起来,等调用commit的时候,统一批处理.下面会对Fragmeng的事务管理做一个代码分析 分

仿知乎程序 fragment的切换以及toolbar在不同页面下显示的menu不同

       我们在看知乎的时候,你会发现,首页,发现,关注,收藏,草稿这五项,你在点击之后进入到相应页面之后,侧滑菜单还在,你左侧滑一下,这个侧滑菜单还在,而提问,左滑屏幕,这个页面就没有,有点像返回上一页的感觉. 从操作来看,五页面应该是fragment之间的切换,而提问是单独的activity.     我们先从几个fragment入手,这里我们建立五fragment页,选择继承自android.support.v4.app.Fragment,因为这五个页面基本上都一样,就是简单的一个布局

对fragment的学习

一直对fragment一知半解,今天在运行一个项目的时候,有用到fragment,所以好好地复习了下fragment的知识: 1.fragment的生命周期: 2.在一个访问fragment中的资源可以在 public void onActivityCreated(Bundle savedInstanceState){}方法中 3. public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle save

Android Acitivity 与 Fragment 声明周期

Activity的生命周期: (1)启动Activity:系统会先调用onCreate方法,然后调用onStart方法,最后调用onResume,Activity进入运行状态. (2)当前Activity被其他Activity覆盖其上或被锁屏:系统会调用onPause方法,暂停当前Activity的执行. Activity -> onFreeze() -> onPause() (3)当前Activity由被覆盖状态回到前台或解锁屏:系统会调用onResume方法,再次进入运行状态. (4)当前