美文网首页
A factory has already been set o

A factory has already been set o

作者: 坑逼的严 | 来源:发表于2019-05-23 10:54 被阅读0次

    说一说setFactory方法,他有两种一是LayoutInflater二是LayoutInflaterCompat,顾名思义LayoutInflaterCompat是兼容包为什么有这个兼容包呢?给大家一个网址,上面写的很清楚,结合源码看更容易理解:http://www.apkbus.com/thread-258751-1-1.html?_dsign=e8073ac8
    大部分人用这个实现了换肤功能,我用这个实现动态注入自定义参数实现滑动动画,效果如图:

    1558578917934.gif
    其中很重要的一步就是如何在viewpager的每一个fragment中获取每一个子view的自定义属性,所以开始的时候用了
    ParallaxFactory factory = new ParallaxFactory(this);
    setFactory2(factory);
    

    当然这里是在一个继承了LayoutInflater调用的,ParallaxFactory是一个继承于Factory2的自定义类,所以可以直接调用LayoutInflater的setFactory2,结果是大于21版本的可以实现。原因在上面已经说了。
    那么在使用LayoutInflaterCompat兼容下

    ParallaxFactory factory = new ParallaxFactory(this);
    LayoutInflaterCompat.setFactory(original, factory);
    

    这时ParallaxFactory 是继承于LayoutInflaterFactory的自定义类了,但是运行报:A factory has already been set on this LayoutInflater。我们追溯看源码,

        /** @deprecated */
        @Deprecated
        public static void setFactory(@NonNull LayoutInflater inflater, @NonNull LayoutInflaterFactory factory) {
            if (VERSION.SDK_INT >= 21) {
                inflater.setFactory2(factory != null ? new LayoutInflaterCompat.Factory2Wrapper(factory) : null);
            } else {
                Factory2 factory2 = factory != null ? new LayoutInflaterCompat.Factory2Wrapper(factory) : null;
                inflater.setFactory2(factory2);
                Factory f = inflater.getFactory();
                if (f instanceof Factory2) {
                    forceSetFactory2(inflater, (Factory2)f);
                } else {
                    forceSetFactory2(inflater, factory2);
                }
            }
    
        }
    

    进入inflater.setFactory2(factory2);

        /**
         * Like {@link #setFactory}, but allows you to set a {@link Factory2}
         * interface.
         */
        public void setFactory2(Factory2 factory) {
            if (mFactorySet) {
                throw new IllegalStateException("A factory has already been set on this LayoutInflater");
            }
            if (factory == null) {
                throw new NullPointerException("Given factory can not be null");
            }
            mFactorySet = true;
            if (mFactory == null) {
                mFactory = mFactory2 = factory;
            } else {
                mFactory = mFactory2 = new FactoryMerger(factory, factory, mFactory, mFactory2);
            }
        }
    

    这个时候mFactorySet为true就报了这个错,如果要深究原因,mFactorySet为什么为true,就很麻烦了,我也没搞清,网上说是AppCompatActivity兼容Activity中把他设置为true了,那怎么解决呢?

    setLayoutInflaterFactory(original);
    ParallaxFactory factory = new ParallaxFactory(this);
    LayoutInflaterCompat.setFactory(original, factory);
    
        public void setLayoutInflaterFactory(LayoutInflater original) {
            LayoutInflater layoutInflater = original;
            try {
                Field mFactorySet = LayoutInflater.class.getDeclaredField("mFactorySet");
                mFactorySet.setAccessible(true);
                mFactorySet.set(layoutInflater, false);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    

    我们在设置工厂前先通过反射设置mFactorySet为false,就行了。发现这这个解决方法后,瞬间觉得许多布局,许多动画效果,自定义属性都可以实现了,再也不拘束于在Textview或Imageview上继承然后封装一层自定义View,直接在他们身上加就行了,哈哈。

    相关文章

      网友评论

          本文标题:A factory has already been set o

          本文链接:https://www.haomeiwen.com/subject/rmxvzqtx.html