我们上一讲,抛出来一个问题,就是当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事务的时候再说。

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

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

    Fragment管理中,不得不谈到的就是它的事务管理,它的事务管理写的很的出彩.我们先引入一个简单经常使用的Fragment事务管理代码片段: FragmentTransaction ft = thi ...

  2. [Android]Volley源代码分析(二)Cache

    Cache作为Volley最为核心的一部分,Volley花了重彩来实现它.本章我们顺着Volley的源代码思路往下,来看下Volley对Cache的处理逻辑. 我们回忆一下昨天的简单代码,我们的入口是 ...

  3. Android HttpURLConnection源代码分析

    Android HttpURLConnection源代码分析 之前写过HttpURLConnection与HttpClient的差别及选择.后来又分析了Volley的源代码. 近期又遇到了问题,想在V ...

  4. Android 消息处理源代码分析(1)

    Android 消息处理源代码分析(1) 在Android中,通常被使用的消息队列的代码在文件夹\sources\android-22\android\os下,涉及到下面几个类文件 Handler.j ...

  5. Android HandlerThread 源代码分析

    HandlerThread 简单介绍: 我们知道Thread线程是一次性消费品,当Thread线程运行完一个耗时的任务之后.线程就会被自己主动销毁了.假设此时我又有一 个耗时任务须要运行,我们不得不又 ...

  6. Android KLog源代码分析

    Android KLog源代码分析 Android KLog源代码分析 代码结构 详细分析 BaseLog FileLog JsonLog XmlLog 核心文件KLogjava分析 遇到的问题 一直 ...

  7. android开发源代码分析--多个activity调用多个jni库的方法

    android开发源代码分析--多个activity调用多个jni库的方法 有时候,我们在开发android项目时会遇到须要调用多个native c/jni库文件,下面是本人以前实现过的方法,假设有知 ...

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

    Android 消息处理源代码分析(1)点击打开链接 继续接着分析剩下的类文件 Looper.java public final class Looper { final MessageQueue m ...

  9. Appium Android Bootstrap源代码分析之启动执行

    通过前面的两篇文章<Appium Android Bootstrap源代码分析之控件AndroidElement>和<Appium Android Bootstrap源代码分析之命令 ...

随机推荐

  1. 定时显示提示控件 TToolTip

    转载过来的,文章出自: http://www.delphifans.com/infoview/Article_3640.html {    修改者:ghs    日期:20071218    功能:在 ...

  2. /etc/passwd 结构

    命令:cat /etc/passwd username:password:uid:gid:allname:homedir:shell 用户名:密码:用户ID:组ID:用户全名:主目录:登录shell ...

  3. 编写 Objective-C 代码

    如果您未曾开发过 iOS 或 Mac OS X 平台的程序,那就需要开始了解它们的首要程序设计语言 Objective-C.Objective-C 并不是一种很难的语言,如果能花一点时间学习,相信您会 ...

  4. codeigniter 分页类练习

    controller page页: <?php class Blog extends CI_Controller{ public function __construct(){ parent:: ...

  5. poj1160Post Office(DP)

    http://poj.org/problem?id=1160 算水过的吧 四重循环没优化 CZ说爆可过 就爆了 dp[i][j] = min(dp[i][j],dp[i-1][g]-s) 第i个点建在 ...

  6. MongoDB中ObjectId的误区,以及引起的一系列问题

    近期对两个应用进行改造,在上线过程中出现一系列问题(其中一部分是由于ObjectId误区导致的) 先来了解下ObjectId: TimeStamp 前 4位是一个unix的时间戳,是一个int类别,我 ...

  7. [039] 微信公众帐号开发教程第15篇-自定义菜单的view类型(访问网页)

    引言及内容概要 距离写上一篇文章<自定义菜单的创建及菜单事件响应>整整过了两个月的时间,那时公众平台还没有开放view类型的菜单.在不久前,微信公众平台悄悄开放了view类型的菜单,却没有 ...

  8. 待修改 nyoj 412 又是一个遗留问题

    测试的数据都正确啊,跟别人正确代码也对比了一下,一直wrong ans,这道题是搞不定了,思路是这样的,一个int 的数, 例如 一个数的二进制是1001100,那么大于这个数的最小的有相同个数1的数 ...

  9. wuzhicms模版语法

    在模版中使用的语法规则: 例如:templates/default/content/show.html 1.变量表示 {$title} 被解析成 <?php echo $title;?> ...

  10. E297: Write error in swap file解决方法

    vi打开配置文件后显示E297: Write error in swap file,检查磁盘发现磁盘满了.使用du –max-depth=1 | sort –n –r 查找大文件所在位置并删除.