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<?事实上这种方法有google的说明。只是光是看了说明也不太明确!我这里分几步来分析这种方法:> 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); } }
(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事实上就是获取单例的方法!这不用多说。
我要说的已经完了!
大家能够自己去总结一下。