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
-
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
-
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
PrivateFactory
- Activity
- 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:
android.widget.
android.webkit.
android.app.
Special Tag
merge
:
-
Must be the root node
-
Root and attachToRoot == true must be passed when the inflate() is called
include
- The parent must be
ViewGroup
type
Changes to API >= 23
-
Android :theme support for overwriting referenced layouts
-
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:
-
If android:layout_width, Android :layout_height are set in the include tag, then all layout_xxx attributes in the referenced layout are ignored
-
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