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

本文深入探讨了Android开发中FragmentPagerAdapter的工作原理,特别是其getItem方法及Fragment的instantiate方法。揭示了Fragment实例化背后的机制,并解释了为何每次都需要创建新的Fragment实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在做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();  这个很简单其实就是获取单例的方法!这不用多说。

我要说的已经完了!  大家可以自己去总结一下!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值