A factory has already been set on this LayoutInflater问题解决

说一说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 on this LayoutInflater问题解决)