android的Fragment解析(一行代码引发的思考)

在做android开发时候,看到一行代码。认为奇怪。于是就有来了个刨根问底。废话不多说。

在写自己的FragmentPagerAdapter的时候,有以下几行代码:

        @Override
        public Fragment getItem(int position) {
            TabInfo info = mTabs.get(position);
            DeskClockFragment f = (DeskClockFragment) Fragment.instantiate(
                    mContext, info.clss.getName(), info.args);
            return f;
        }
对于getItem这种方法,大家都非常熟悉。从上面的代码能够知道,每一次回调getItem这个函数时候。似乎都会创建一个DeskClockFragment实例,这显然不是一个好的办法,为何,从Adapter的优化方法能够知道,DeskClockFragment这个实例假设能每次都重用不是更好吗!

难道是google写的这行代码我们还能够优化吗?答案当然是否定的!要搞清楚这个问题,我们要看看Fragment的这种方法instantiate究竟做了些什么。

        以下我们来看看instantiate这种方法的定义:

    public static Fragment instantiate(Context context, String fname, Bundle args) {
        try {
            Class<?

> clazz = sClassMap.get(fname); if (clazz == null) { // Class not found in the cache, see if it's real, and try to add it clazz = context.getClassLoader().loadClass(fname); if (!Fragment.class.isAssignableFrom(clazz)) { throw new InstantiationException("Trying to instantiate a class " + fname + " that is not a Fragment", new ClassCastException()); } sClassMap.put(fname, clazz); } Fragment f = (Fragment)clazz.newInstance(); if (args != null) { args.setClassLoader(f.getClass().getClassLoader()); f.mArguments = args; } return f; } catch (ClassNotFoundException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an" + " empty constructor that is public", e); } catch (java.lang.InstantiationException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an" + " empty constructor that is public", e); } catch (IllegalAccessException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an" + " empty constructor that is public", e); } }

事实上这种方法有google的说明。只是光是看了说明也不太明确!我这里分几步来分析这种方法:

(1)instantiate这种方法是一个static的方法!那就说明,这种方法跟创建的这个对象是没有直接关系的。

这种方法是Fragment的这个class的静态方法!

(2)接着我们来看看sClassMap是个什么东西,在Fragment里面有例如以下代码对sClassMap的定义:

    private static final HashMap<String, Class<?>> sClassMap =
            new HashMap<String, Class<?>>();
对于sClassMap有两个非常特别的修饰:static和final。这说明sClassMap是属于全部Fragment实例的、是用于记录全部载入过的Fragment的。

只是,奇怪的是在Fragment里面sClassMap也仅仅是在instantiate这种方法里面用到!

那就奇怪了。寻常我们用一个Fragment时候也没有说要去调用instantiate这种方法呀!

事实上不然!  在Activity里面。有一个方法引起了我的注意: public View onCreateView(View parent, String name, Context context, AttributeSet attrs)。这里我贴出该方法的主要代码:

  public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
        if (!"fragment".equals(name)) {
            return onCreateView(name, context, attrs);
        }
...
...
        if (fragment == null) {
            fragment = Fragment.instantiate(this, fname);
            fragment.mFromLayout = true;
...
...
}
看到了吗?事实上寻常我们使用的时候更本不用自己去调用Fragment的方法:instantiate,而是我们的Activity会自己去调用!

(3)接下来我们看看这行代码:Fragment f = (Fragment)clazz.newInstance();  这个非常easy事实上就是获取单例的方法!这不用多说。

我要说的已经完了!

 大家能够自己去总结一下。

posted @ 2017-08-20 10:27  jzdwajue  阅读(220)  评论(0编辑  收藏  举报