LayoutInflater.SetFactory()学习

2016-05-30  本文已影响938人  shuixingge

参考资料1
参考资料2

一:基本概念

LayoutInflater.setFactory():
LayoutInflater提供了两个方法,分别是setFactory()和setFactory2(),其中setFactory2()是在sdk>11的时候引入的;
LayoutInflaterFactory:
仅有一个onCreateView()方法,用来创建View;

  public interface LayoutInflaterFactory {

    /**
     * Hook you can supply that is called when inflating from a LayoutInflater.
     * You can use this to customize the tag names available in your XML
     * layout files.
     *
     * @param parent The parent that the created view will be placed
     * in; <em>note that this may be null</em>.
     * @param name Tag name to be inflated.
     * @param context The context the view is being created in.
     * @param attrs Inflation attributes as specified in XML file.
     *
     * @return View Newly created view. Return null for the default
     *         behavior.
     */
    public View onCreateView(View parent, String name, Context context, AttributeSet attrs);

}

LayoutInflaterCompat:LayoutInflater的兼容类;

二:自定义LayoutInflaterFactory

用处:
我们可以在onCreateView中根据name属性来做一些逻辑操作,如把TextView替换成自定义View或者其他控件,这样做的好处可以提高效率,因为系统创建要有一些逻辑要走,最终通过反射来创建,发射会影响性能;

   public class FactoryActivity extends AppCompatActivity {
    private static final String TAG = "FactoryActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        LayoutInflaterCompat.setFactory(LayoutInflater.from(this), new LayoutInflaterFactory() {
            //重写onCreateView()
            @Override
            public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
                Log.i(TAG, "name = " + name);
                int n = attrs.getAttributeCount();
                for (int i = 0; i < n; i++) {
                    Log.e(TAG, attrs.getAttributeName(i) + " , " + attrs.getAttributeValue(i));
                }
                return null;
            }
        });
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_factory);
    }
}

会打印出信息如下:
The Activity's LayoutInflater already has a Factory installed so we can not install AppCompat's

1 2

The Activity's LayoutInflater already has a Factory installed so we can not install AppCompat's
原因如下:因为AppCompatActivity内部也调用了setFactory,所以我们再自己调用setFactory就会出现上面的信息;

影响: 如果我们在系统之前调用了setFactory,就会打印上面的info信息,并且造成其setFactroy不会生效,会造成没有办法使用一些新的特性,比如tint等
AppCompatActivity.onCreate()

 @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        getDelegate().installViewFactory();
        getDelegate().onCreate(savedInstanceState);
        super.onCreate(savedInstanceState);
    }

AppCompatActivity-> AppCompatDelegate ->AppCompatDelegateImplV7
可以看出AppCompatDelegateImplV7实现了LayoutInflaterFactory;

AppCompatDelegateImplV7
**AppCompatDelegateImplV7.installViewFactory() **
  @Override
    public void installViewFactory() {
        LayoutInflater layoutInflater = LayoutInflater.from(mContext);
        if (layoutInflater.getFactory() == null) {
           //注意这里,如果设置了自定义的Factory,那么该方法不会被调用;从而AppCompatDelegateImplV7.onCreateView方法也不会被调用;
            LayoutInflaterCompat.setFactory(layoutInflater, this);
        } else {
            Log.i(TAG, "The Activity's LayoutInflater already has a Factory installed"
                    + " so we can not install AppCompat's");
        }
    }

AppCompatDelegateImplV7.onCreateView()


      @Override
    public final View onCreateView(View parent, String name,
            Context context, AttributeSet attrs) {
        // First let the Activity's Factory try and inflate the view
          //首先使用Activity的Factory来加载View;
        final View view = callActivityOnCreateView(parent, name, context, attrs);
        if (view != null) {
            return view;
        }
          //如果Activity的Factory不能处理,那么就调用AppCompatDelegateImplV7.createView()
        // If the Factory didn't handle it, let our createView() method try
        return createView(parent, name, context, attrs);
    }

解决方法: 在自己设置factory中,调用系统的创建view的代码;

    LayoutInflaterCompat.setFactory(LayoutInflater.from(this), new LayoutInflaterFactory()
{
    @Override
    public View onCreateView(View parent, String name, Context context, AttributeSet attrs)
    {
        //你可以在这里直接new自定义View

        //你可以在这里将系统类替换为自定义View

         //appcompat 创建view代码
        AppCompatDelegate delegate = getDelegate();
        View view = delegate.createView(parent, name, context, attrs);

        return view;
    }
});

原因解释:AppCompatDelegate.createView会通过一系列方法调用链,最后走到如下的代码,这部分代码会把控件自动的替换成Appcompat的控件,从而支持一些新的特性;所以只要调用了AppCompatDelegate.createView()就能保留新特性

switch (name) {
            case "TextView":
                view = new AppCompatTextView(context, attrs);
                break;
            case "ImageView":
                view = new AppCompatImageView(context, attrs);
                break;
            case "Button":
                view = new AppCompatButton(context, attrs);
                break;
            case "EditText":
                view = new AppCompatEditText(context, attrs);
                break;
            case "Spinner":
                view = new AppCompatSpinner(context, attrs);
                break;
            case "ImageButton":
                view = new AppCompatImageButton(context, attrs);
                break;
            case "CheckBox":
                view = new AppCompatCheckBox(context, attrs);
                break;
            case "RadioButton":
                view = new AppCompatRadioButton(context, attrs);
                break;
            case "CheckedTextView":
                view = new AppCompatCheckedTextView(context, attrs);
                break;
            case "AutoCompleteTextView":
                view = new AppCompatAutoCompleteTextView(context, attrs);
                break;
            case "MultiAutoCompleteTextView":
                view = new AppCompatMultiAutoCompleteTextView(context, attrs);
                break;
            case "RatingBar":
                view = new AppCompatRatingBar(context, attrs);
                break;
            case "SeekBar":
                view = new AppCompatSeekBar(context, attrs);
                break;
        }
上一篇下一篇

猜你喜欢

热点阅读