当前位置: 代码迷 >> Android >> [Android]Fragment源码分析(1) 构造
  详细解决方案

[Android]Fragment源码分析(1) 构造

热度:483   发布时间:2016-04-28 04:26:14.0
[Android]Fragment源码分析(一) 构造

Fragment是Android3.0之后提供的api,被大家广泛所熟知的主要原因还是因为随即附带的ViewPager控件。虽然我并不喜欢用它,但是它确实是一个相对不错的控件。还是我的一贯作风,我将从源码上向大家展示什么是Fragment。我们先写一个简单的代码对Fragment有个直观的认识:(为了保证我们方便调试,我们可以直接使用V4提供的源码包)

FragmentTransaction t = getSupportFragmentManager().beginTransaction();        t.add(android.R.id.content, new TestFragment1());        t.commitAllowingStateLoss();

通过这些代码,我们就可以生成一个Fragment,并且我们能在屏幕上直观的看到这个Fragment所要说明的界面。那么一个Fragment是否就是一个控件,或者是一个window?或者是视图的一部分?当然不是。我们来看Fragment的继承树:

public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener

你根本看不到任何View的影子。我在加入M公司之前参加过不少公司的面试,面试官总是斩钉截铁的告诉我Fragment就是一个片段就是用来显示大屏幕下的一部分控件。他们这么坚定的问题在于被Fragment所带来的ViewPager这种好用的控件和可以在xml配置这个功能所蛊惑,他们缺乏对LayoutInflater源码的认识。实际上,这点,你不得不对Android这部分代码的开发者致敬,因为他让代码有了无限扩展的可能。

我们先来看下FragmentActivity:

android.support.v4.app.FragmentActivity
@Override    protected void onCreate(Bundle savedInstanceState) {        mFragments.attachActivity(this, mContainer, null);        // Old versions of the platform didn't do this! <pre name="code" class="java">       if (getLayoutInflater().getFactory() == null) {            getLayoutInflater().setFactory(this);        }        

我们知道Activity才是Fragment的根,Fragment作为片段是相对Activity而言,Activity对于Fragment来说本质上是个控制器,用于分发不同的状态和业务。在onCreate的前半部分,有一个很重要的设置:

       if (getLayoutInflater().getFactory() == null) {            getLayoutInflater().setFactory(this);        }        

这个是用来干嘛的呢?~实际上,你如果了解一点LayoutInflater的源码其实并不会感到陌生,因为这个接口是为了构造你的View而存在。这就是伟大的Androidsdk开发者给你提供的扩展机会,不论你配置的东西是否继承于View,只要你实现了这个接口,你就可以按照既定的规则构造出View。这个接口的实现方法在:

 @Override    public View onCreateView(String name, Context context, AttributeSet attrs) {        if (!"fragment".equals(name)) {            return super.onCreateView(name, context, attrs);        }        。。。

我们先取前半部分代码,我们很清楚的看出,实际上fragment标签是被FragmentActivity特殊处理了。不知道你们是否理解了,如果不特殊处理,那么交给默认逻辑处理的话,你的对象由于不继承View一定会导致程序崩溃。那么我们接着往下看:

if (fragment == null) {            fragment = Fragment.instantiate(this, fname);            fragment.mFromLayout = true;            fragment.mFragmentId = id != 0 ? id : containerId;            fragment.mContainerId = containerId;            fragment.mTag = tag;            fragment.mInLayout = true;            fragment.mFragmentManager = mFragments;            fragment.onInflate(this, attrs, fragment.mSavedFragmentState);            mFragments.addFragment(fragment, true);        }
可以看出fragment的生成是通过Fragment的静态工厂方法帮你生成。而且生成之后将纳入mFragments的管理。那么什么是mFragments?实际上mFragments是FragmentManager对象,这是整个Framgent管理中非常重要的对象。但是,我们还是没有看到View的影子,不要着急,我们接着往下读:

if (fragment.mView == null) {            throw new IllegalStateException("Fragment " + fname                    + " did not create a view.");        }        if (id != 0) {            fragment.mView.setId(id);        }        if (fragment.mView.getTag() == null) {            fragment.mView.setTag(tag);        }        return fragment.mView;
发现了么?实际上,最终并不返回Fragment本身,而是返回Fragment的成员mView。但是我们并没有看到对这个成员的附值呀?实际上,在mFragments将Fragment add之后,已经对View进行赋值。不过我这里先卖个关子,下一章我们谈到Fragment的状态的时候我会回头来解释这个逻辑。




  相关解决方案