LayoutInflater

Android:11, Api: 30


Factory, Factory2

Factory2 is an extension (subclass) of Factory. The method name is onCreateView but passes an extra parent

It can only be set once and must be non-empty. To reset, cloneInContext() generates new LayoutInflater objects

Design patterns

  1. Decorator pattern that merges multiple factories

    //setFactory is similar
    public void setFactory2(Factory2 factory) {
        if (mFactorySet) {
            // Can only be set once, either Factory or Factory2
            throw new IllegalStateException("A factory has already been set on this LayoutInflater");
        }
        if (factory == null) {
            / / is not empty
            throw new NullPointerException("Given factory can not be null");
        }
        mFactorySet = true;
        if (mFactory == null) {
            mFactory = mFactory2 = factory;
        } else {
            // The decorator pattern incorporates multiple factories
            mFactory = mFactory2 = newFactoryMerger(factory, factory, mFactory, mFactory2); }}// The decorator pattern is the main implementation class
    private static class FactoryMerger implements Factory2 {
        private final Factory mF1, mF2;
        private final Factory2 mF12, mF22;
    
        FactoryMerger(Factory f1, Factory2 f12, Factory f2, Factory2 f22) {
            mF1 = f1;
            mF2 = f2;
            mF12 = f12;
            mF22 = f22;
        }
    
        @Nullable
        public View onCreateView(@NonNull String name, @NonNull Context context,
                @NonNull AttributeSet attrs) {
            View v = mF1.onCreateView(name, context, attrs);
            if(v ! =null) return v;
            return mF2.onCreateView(name, context, attrs);
        }
    
        @Nullable
        public View onCreateView(@Nullable View parent, @NonNull String name,
                @NonNull Context context, @NonNull AttributeSet attrs) { View v = mF12 ! =null ? mF12.onCreateView(parent, name, context, attrs)
                    : mF1.onCreateView(name, context, attrs);
            if(v ! =null) return v;
            returnmF22 ! =null? mF22.onCreateView(parent, name, context, attrs) : mF2.onCreateView(name, context, attrs); }}Copy the code
  2. Chain of Responsibility model

    @Nullable
    public final View tryCreateView(@Nullable View parent, @NonNull String name,
        @NonNull Context context,
        @NonNull AttributeSet attrs) {
        if (name.equals(TAG_1995)) {
            / / eggs
            // Let's party like it's 1995!
            return new BlinkLayout(context, attrs);
        }
    
        View view;
        // Responsibility chain mode, until one can parse to generate the current label
        if(mFactory2 ! =null) {
            view = mFactory2.onCreateView(parent, name, context, attrs);
        } else if(mFactory ! =null) {
            view = mFactory.onCreateView(name, context, attrs);
        } else {
            view = null;
        }
    
        if (view == null&& mPrivateFactory ! =null) {
            view = mPrivateFactory.onCreateView(parent, name, context, attrs);
        }
    
        return view;
    }
    
    Copy the code

Using the example

AppCompatViewInflater in the appCompat package, which sets
in XML, generates AppCompatTextView class objects at run time

PrivateFactory

  1. Activity
  2. Android. App. FragmentManager (own) system

Used to parse fragment tags, the source code is not available

Filter

Check whether the current tag is allowed to be created, for example: notification, controls in the widget need to have the @remoteView annotation, which is filtered by Filter

Parsing the label

createViewFromTag

PhoneLayoutInflater

LayoutInflater’s only implementation class, mainly for no. Add a prefix to the tag and try to create

Prefixes are:

  1. android.widget.
  2. android.webkit.
  3. android.app.

Special Tag

merge:

  1. Must be the root node

  2. Root and attachToRoot == true must be passed when the inflate() is called

include

  1. The parent must beViewGrouptype

Changes to API >= 23

  1. Android :theme support for overwriting referenced layouts

  2. Support parsing? Attr, such as:

    <! -- styles.xml -->
    <style name="IncludeTheme">
        <item name="include_layout">@layout/included_demo</item>
    </style>
    
    <! -- layout.xml -->
    <include layout="? attr/include_layout" android:theme="@style/IncludeTheme"/>
    Copy the code

Layout parameter layout_xxx ignored unless both layout_width and layout_height are also specified on <include> tag

On the source code:

private void parseInclude(XmlPullParser parser, Context context, View parent, AttributeSet attrs) throws XmlPullParserException, IOException {
    / /... Put the head
    // The XML parser for the referenced layout
    final XmlResourceParser childParser = context.getResources().getLayout(layout);
    // Attributes of the referenced layout
    final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
    ViewGroup.LayoutParams params = null;
    try {
        // Try parsing LayoutParams in the 
      
        tag
      
        params = group.generateLayoutParams(attrs);
    } catch (RuntimeException e) {
        // Ignore, just fail over to child attrs.
    }
    if (params == null) {
        // If the 
      
        tag does not resolve, go to the referenced layout to get it
      
        params = group.generateLayoutParams(childAttrs);
    }
    view.setLayoutParams(params);
    / /... Go to the end
}
Copy the code

See the source code:

  1. If android:layout_width, Android :layout_height are set in the include tag, then all layout_xxx attributes in the referenced layout are ignored

  2. If the width && height is not set in the include tag, any layout_xxx attribute that is set in the include tag is ignored.

blink

BlinkLayout egg tag, twinkle, twinkle

requestFocus

Call view.restoreDefaultFocus () to get the focus

tag

SetTag (key, value) : setTag(key, value)

ContextThemeWrapper

When parsing a label with an Android :theme attribute, the ContextThemeWrapper object is generated, which is used to generate the control object, so sometimes the Activity type is not necessarily retrieved in view.getContext ()

View createViewFromTag(View parent, String name, Context context, AttributeSet attrs, boolean ignoreThemeAttr) {
    // ...

    if(! ignoreThemeAttr) {final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
        final int themeResId = ta.getResourceId(0.0);
        if(themeResId ! =0) {
            / / and see this
            context = new ContextThemeWrapper(context, themeResId);
        }
        ta.recycle();
    }

    if (-1 == name.indexOf('. ')) {
        / / look at this again
        view = onCreateView(context, parent, name, attrs);
    } else {
        / / look at this again
        view = createView(context, name, null, attrs);
    }

    // ...
}
Copy the code

PrecompiledView

API 29, Android 10 has been in the code since the beginning. Parse XML into classes (similar to Android-x2j, X2C) to reduce IO read layout time and avoid reflection. However, until now (Android 11, API 30) releases have been turned off by default

data