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 的生命周期方法

 
 

Fragment 操作原理的更多相关文章

  1. 浅谈 Fragment 生命周期

    版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...

  2. 札记:Fragment基础

    Fragment概述 在Fragment出现之前,Activity是app中界面的基本组成单位,值得一提的是,作为四大组件之一,它是需要"注册"的.组件的特性使得一个Activit ...

  3. EventBus实现activity跟fragment交互数据

    最近老是听到技术群里面有人提出需求,activity跟fragment交互数据,或者从一个activity跳转到另外一个activity的fragment,所以我给大家介绍一个开源项目,EventBu ...

  4. Android:Activity+Fragment及它们之间的数据交换.

    Android:Activity+Fragment及它们之间的数据交换 关于Fragment与Fragment.Activity通信的四种方式 比较好一点的Activity+Fragment及它们之间 ...

  5. Android中Fragment和ViewPager那点事儿(仿微信APP)

    在之前的博文<Android中使用ViewPager实现屏幕页面切换和引导页效果实现>和<Android中Fragment的两种创建方式>以及<Android中Fragm ...

  6. Android开发学习—— Fragment

    #Fragment* 用途:在一个Activity里切换界面,切换界面时只切换Fragment里面的内容* 生命周期方法跟Activity一致,可以理解把其为就是一个Activity* 定义布局文件作 ...

  7. Android中Fragment与Activity之间的交互(两种实现方式)

    (未给Fragment的布局设置BackGound) 之前关于Android中Fragment的概念以及创建方式,我专门写了一篇博文<Android中Fragment的两种创建方式>,就如 ...

  8. Android中Fragment的两种创建方式

    fragment是Activity中用户界面的一个行为或者是一部分.你可以在一个单独的Activity上把多个Fragment组合成为一个多区域的UI,并且可以在多个Activity中再使用.你可以认 ...

  9. Android Fragment 剖析

    1.Fragment如何产生?2.什么是Fragment Android运行在各种各样的设备中,有小屏幕的手机,超大屏的平板甚至电视.针对屏幕尺寸的差距,很多情况下,都是先针对手机开发一套App,然后 ...

随机推荐

  1. Effective C++ -----条款24:若所有参数皆需类型转换,请为此采用non-member函数

    如果你需要为某个函数的所有参数(包括被this指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member.

  2. Divide and conquer:Telephone Lines(POJ 3662)

    电话线 题目大意:一堆电话线要你接,现在有N个接口,总线已经在1端,要你想办法接到N端去,电话公司发好心免费送你几段不用拉网线,剩下的费用等于剩余最长电话线的长度,要你求出最小的费用. 这一看又是一个 ...

  3. Divide and conquer:Matrix(POJ 3685)

    矩阵 题目大意:矩阵里面的元素按i*i + 100000 * i + j*j - 100000 * j + i*j填充(i是行,j是列),求最小的M个数 这一题要用到两次二分,实在是二分法的经典,主要 ...

  4. springmvc 文件下传、上载、预览。以二进制形式存放到数据库(转载)

    springmvc 文件上传.下载.预览.以二进制形式存放到数据库.数据库中的关于传入附件的字段我写了2个:一个存放内容accessory,一个存放文件的后缀filetype 上传:首先需要2个必须的 ...

  5. 【leetcode】Sum Root to Leaf Numbers(hard)

    Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number ...

  6. increadbuild重装

    客户端和服务端都重装,可能需要去任务管理其中停止相关的服务,重装之前要去注册表中删除旧的注册表项.一般情况下incredibuild对应的位置是:64位系统HKEY_CLASSES_ROOT\\Wow ...

  7. swift学习记录之代理

    /// 访客视图的协议 protocol VisitorLoginViewDelegate: NSObjectProtocol { func visitorLoginViewWillRegister( ...

  8. iOS应用架构谈(二):View层的组织和调用方案(中)

    iOS客户端应用架构看似简单,但实际上要考虑的事情不少.本文作者将以系列文章的形式来回答iOS应用架构中的种种问题,本文是其中的第二篇,主要讲View层的组织和调用方案.中篇主要讨论MVC.MVCS. ...

  9. AI调色板

    AI新建图层时,要选择CMYK模式,才能出现如下图所示调色板,如果选RGB模式,那么调整颜色的时候只能通过输入RGB.

  10. MysqlDumpslow

    可以帮助分析慢查询. 选项: -n 10 列出最近10条慢查询 如: mysqldumpslow