[Android]Fragment源代码分析(二) 状态

我们上一讲,抛出来一个问题,就是当Activity的onCreateView的时候,是怎样构造Fragment中的View參数。要回答这个问题我们先要了解Fragment的状态,这是Fragment管理中很重要的一环。我们先来看一下FragmentActivity提供的一些核心回调:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        mFragments.attachActivity(this, mContainer, null);
        // Old versions of the platform didn't do this!
        if (getLayoutInflater().getFactory() == null) {
            getLayoutInflater().setFactory(this);
        }

        super.onCreate(savedInstanceState);
....
        mFragments.dispatchCreate();
    }

我们跟入mFragments.dispatchCreate方法中:

public void dispatchCreate() {
        mStateSaved = false;
        moveToState(Fragment.CREATED, false);
    }

我们看到,对于FragmentManager来说,做了一次状态转换。我上一篇说过FragmentManager是及其重要的类,它承担了Fragment管理最为核心的工作。它有它自身的状态机,而它的状态,能够理解为与Activity本身基本同步。

在Fm里面维护自己的一个状态,当你导入一个Fragment的时候,Fm的目的,就是为了让Fragment和自己的状态基本保持一致.

void moveToState(int newState, int transit, int transitStyle, boolean always) {
        if (mActivity == null && newState != Fragment.INITIALIZING) {
            throw new IllegalStateException("No activity");
        }

        if (!always && mCurState == newState) {
            return;
        }
        mCurState = newState;
        if (mActive != null) {
            boolean loadersRunning = false;
            for (int i = 0; i < mActive.size(); i++) {
                Fragment f = mActive.get(i);
                if (f != null) {
                    moveToState(f, newState, transit, transitStyle, false);
                    if (f.mLoaderManager != null) {
                        loadersRunning |= f.mLoaderManager.hasRunningLoaders();
                    }
                }
            }

            ...
        }
    }

我们看到,FragmentManager的每一次状态变更,都会引起mActive里面的Fragment的状态变更。而mActive是全部纳入FragmentManager管理的Fragment容器。我们来看一下Fragment的几个状态:

static final int INITIALIZING = 0;     // Not yet created.
    static final int CREATED = 1;          // Created.
    static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
    static final int STOPPED = 3;          // Fully created, not started.
    static final int STARTED = 4;          // Created and started, not resumed.
    static final int RESUMED = 5;          // Created started and resumed.

能够看出实际上,你的状态越靠后你的状态值越大,实际上在Fm的管理中,也巧妙的用到了这一点。

 if (f.mState < newState)
{
  ...
} else {
  ...
}

对于f.mState<newState能够理解为创造的过程。同一时候我们也能找到我们上一篇文章的问题的答案:

if (f.mFromLayout) {
                    // For fragments that are part of the content view
                    // layout, we need to instantiate the view immediately
                    // and the inflater will take care of adding it.
                    f.mView = f.performCreateView(
                            f.getLayoutInflater(f.mSavedFragmentState), null,
                            f.mSavedFragmentState);
                    if (f.mView != null) {
                        f.mInnerView = f.mView;
                        f.mView = NoSaveStateFrameLayout.wrap(f.mView);
                        if (f.mHidden)
                            f.mView.setVisibility(View.GONE);
                        f.onViewCreated(f.mView, f.mSavedFragmentState);
                    } else {
                        f.mInnerView = null;
                    }
                }

f.mFromLayout代表的是你这个Fragment的生成是否是从layout.xml文件里生成的。而它的View的生成是调用performCreateView来生成的。

View performCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (mChildFragmentManager != null) {
            mChildFragmentManager.noteStateNotSaved();
        }
        return onCreateView(inflater, container, savedInstanceState);
    }

对,这里就是我们很熟悉的onCreateView回调的出处。

当然我们如今还是属于Fragment.INITIALIZING这个状态。但实际上,我们在调用Fragment的时候FragmentManageer已经进入了Create状态。也就是说newState參数应该是Create才对。

所以我们接着代码往下走:

 case Fragment.CREATED:
                if (newState > Fragment.CREATED) {
                    if (!f.mFromLayout) {
                        ViewGroup container = null;
                        if (f.mContainerId != 0) {
                            container = (ViewGroup) mContainer
                                    .findViewById(f.mContainerId);
                            if (container == null && !f.mRestored) {
                                throwException(new IllegalArgumentException(
                                        "No view found for id 0x"
                                                + Integer
                                                        .toHexString(f.mContainerId)
                                                + " ("
                                                + f.getResources()
                                                        .getResourceName(
                                                                f.mContainerId)
                                                + ") for fragment " + f));
                            }
                        }
                        f.mContainer = container;
                        f.mView = f.performCreateView(
                                f.getLayoutInflater(f.mSavedFragmentState),
                                container, f.mSavedFragmentState);
                        if (f.mView != null) {
                            f.mInnerView = f.mView;
                            f.mView = NoSaveStateFrameLayout.wrap(f.mView);
                            if (container != null) {
                                Animation anim = loadAnimation(f, transit,
                                        true, transitionStyle);
                                if (anim != null) {
                                    f.mView.startAnimation(anim);
                                }
                                container.addView(f.mView);
                            }
                            if (f.mHidden)
                                f.mView.setVisibility(View.GONE);
                            f.onViewCreated(f.mView, f.mSavedFragmentState);
                        } else {
                            f.mInnerView = null;
                        }
                    }

                    f.performActivityCreated(f.mSavedFragmentState);
                    if (f.mView != null) {
                        f.restoreViewState(f.mSavedFragmentState);
                    }
                    f.mSavedFragmentState = null;
                }

我们看到实际上这段代码是对FragmentManager状态是Create以上状态且Fragment的导入并非採用layout.xml方式导入的处理。这是为什么呢?由于在onCreate之后,基本上你的控件已经在Create状态的时候生成的差点儿相同了,你所要做的就是在生成的控件中找到Fragment相应的容器,然后装入你的控件。

同一时候,我们也看到了对Fragment的动画处理:

if (f.mView != null) {
                            f.mInnerView = f.mView;
                            f.mView = NoSaveStateFrameLayout.wrap(f.mView);
                            if (container != null) {
                                Animation anim = loadAnimation(f, transit,
                                        true, transitionStyle);
                                if (anim != null) {
                                    f.mView.startAnimation(anim);
                                }
                                container.addView(f.mView);
                            }
                            if (f.mHidden)
                                f.mView.setVisibility(View.GONE);
                            f.onViewCreated(f.mView, f.mSavedFragmentState);
                        } else {
                            f.mInnerView = null;
                        }

而这样的动画的处理和參数的配置,我们留到后面讲到Fragment事务的时候再说。

时间: 2024-10-09 23:16:46

[Android]Fragment源代码分析(二) 状态的相关文章

[Android]Fragment源代码分析(三) 事务

Fragment管理中,不得不谈到的就是它的事务管理,它的事务管理写的很的出彩.我们先引入一个简单经常使用的Fragment事务管理代码片段: FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction(); ft.add(R.id.fragmentContainer, fragment, "tag"); ft.addToBackStack("<span style="f

[Android]Fragment源码分析(二) 状态

我们上一讲,抛出来一个问题,就是当Activity的onCreateView的时候,是如何构造Fragment中的View参数.要回答这个问题我们先要了解Fragment的状态,这是Fragment管理中非常重要的一环.我们先来看一下FragmentActivity提供的一些核心回调: @Override protected void onCreate(Bundle savedInstanceState) { mFragments.attachActivity(this, mContainer,

android原生browser分析(二)--界面篇

我们先看一张浏览器的主界面,上面标示浏览器界面各部分对应的类,这里是以平板上的界面为例.给张图是为了给大家一个直观的感觉. BrowserActivity是整个应用的主界面,在onCreate中创建了Controller对象,Controller对象是整个应用最重要的管理类,这个后面再说. @Override public void onCreate(Bundle icicle) { mController = createController(); } Controller的创建中新建了UI类

Android init源代码分析(2)init.rc解析

本文描述init.rc脚本解析以及执行过程,读完本章后,读者应能 (1) 了解init.rc解析过程 (2) 定制init.rc init.rc介绍 init.rc是一个文本文件,可认为它是Android系统启动脚本.init.rc文件中定义了环境变量配置.系统进程启动,分区挂载,属性配置等诸多内容.init.rc具有特殊的语法.init源码目录下的readme.txt中详细的描述了init启动脚本的语法规则,是试图定制init.rc的开发者的必读资料. Android启动脚本包括一组文件,包括

Android 消息处理源代码分析(2)

Android 消息处理源代码分析(1)点击打开链接 继续接着分析剩下的类文件 Looper.java public final class Looper { final MessageQueue mQueue; //消息队列 final Thread mThread; //Looper联系的线程 public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { /

Android init源代码分析(1)概要分析

功能概述 init进程是Android内核启动的第一个进程,其进程号(pid)为1,是Android系统所有进程的祖先,因此它肩负着系统启动的重要责任.Android的init源代码位于system/core/init/目录下,伴随Android系统多个版本的迭代,init源代码也几经重构. 目前Android4.4源代码中,init目录编译后生成如下Android系统的三个文件,分别是 /init /sbin/ueventd-->/init /sbin/watchdogd-->/init 其

Android HandlerThread 源代码分析

HandlerThread 简单介绍: 我们知道Thread线程是一次性消费品,当Thread线程运行完一个耗时的任务之后.线程就会被自己主动销毁了.假设此时我又有一 个耗时任务须要运行,我们不得不又一次创建线程去运行该耗时任务.然而.这样就存在一个性能问题:多次创建和销毁线程是非常耗 系统资源的.为了解这样的问题,我们能够自己构建一个循环线程Looper Thread.当有耗时任务投放到该循环线程中时.线程运行耗 时任务,运行完之后循环线程处于等待状态,直到下一个新的耗时任务被投放进来.这样一

Android KLog源代码分析

Android KLog源代码分析 Android KLog源代码分析 代码结构 详细分析 BaseLog FileLog JsonLog XmlLog 核心文件KLogjava分析 遇到的问题 一直使用这个库.但没有细致研究.今天就来研究一下.该库的地址: KLog,在这里先感谢下作者.棒棒哒! 代码结构 整个代码的结构非常easy.例如以下: library klog BaseLog.java FileLog.java JsonLog.java XmlLog.java KLog.java K

CM android的CMUpdater分析(二)

至于为何要在这里讲解android系统源码中的系统更新,我已经在上一篇< CM android的CMUpdater分析(一)>中介绍了.在上一篇中,主要讲解了在eclipse中如何搭建系统应用的开发环境,现在我们就使用eclipse来分析CMUpdater源码.该系统更新是CM修改原生android的基础上实现的.通过分析android系统的应用源码,可以学到一些很好的思想和编程方法学.好了,废话少说,现在就开始我们的学习之旅. 首先,在开始介绍之前,我先把之前根据CMUpdater源码分析来