学习阅读源码笔记。
LayoutInflater 的主要作用是将layout布局文件实例化为相应的 View 对象。
经常的用法是一下三种,第一种是调用的第二种,第二种调用的第三种。他们的区别主要是区别在第二个参数parent参数上。
java View.inflate(this, R.layout.activity_main, null); LayoutInflater.from(this).inflate(R.layout.activity_main, null); LayoutInflater.from(this).inflate(R.layout.activity_main, null, false);
Activity和AppCompatActivity的onCreate中的setContentView方法的执行流程是不一样的。在继承AppCompatActivity的情况下,如果xml中使用了例如TextView,那么会自动的替换成AppCompatTextView。而且创建的方式是通过反射。 是通过LayoutInflater的setFactory2的方法进行了拦截。
Activity的setContentView过程
添加view的过程
1,在activity创建后进行,创建phoneWindow实列。
2,初始化DectorView
3,找到DectorView中的contentId对象添加view
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor(); // 在该处初始化了decor
}
mLayoutInflater.inflate(layoutResID, mContentParent);
}初始化decor的过程,在generateDecor()方法中生成了decorview。在generateLayout中根据app配置的样式进行各种判断,加载不同的系统准备好的layout文件。例如有titlebar或者全空白的layout。
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor); // 将decor传过去
}
}
}protected ViewGroup generateLayout(DecorView decor) {
TypedArray a = getWindowStyle();
mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
if (mIsFloating) {
setLayout(WRAP_CONTENT, WRAP_CONTENT);
setFlags(0, flagsToUpdate);
} else {
setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
}
// notitle 根据样式中的属性配置界面
if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
requestFeature(FEATURE_NO_TITLE);
} else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
requestFeature(FEATURE_ACTION_BAR);
}
if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) {
requestFeature(FEATURE_ACTION_BAR_OVERLAY);
}
if (a.getBoolean(R.styleable.Window_windowActionModeOverlay, false)) {
requestFeature(FEATURE_ACTION_MODE_OVERLAY);
}
if (a.getBoolean(R.styleable.Window_windowSwipeToDismiss, false)) {
requestFeature(FEATURE_SWIPE_TO_DISMISS);
}
WindowManager.LayoutParams params = getAttributes();
if (params.windowAnimations == 0) {
params.windowAnimations = a.getResourceId(
R.styleable.Window_windowAnimationStyle, 0);
}
// Inflate the window decor. 填充decor
int layoutResource; // 进行各种判断来进行对该值的赋值 ,找到一个合适的资源添加到dector中
int features = getLocalFeatures();
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
layoutResource = R.layout.screen_swipe_dismiss; // 系统布局
} else if ((features & (1 << FEATURE_ACTION_BAR)) == 0) {
layoutResource = R.layout.screen_progress;
} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
layoutResource = R.layout.screen_simple_overlay_action_mode;
} else {
// Embedded, so no decoration is needed.
layoutResource = R.layout.screen_simple; //
// System.out.println("Simple!");
}
mDecor.startChanging();//加载系统资源,实列化出来。添加到decor中
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;// ID_ANDROID_CONTENT 该id为系统资源layout中的framelayout的id,用来包含自己的布局。
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);// findViewById 是调用的decorviewview的findviewbyId,所以改view是在decorview中
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
} return contentParent;
}
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
installDecor 对decor进行了创建(new),DecorView继承自FrameLayout,通过findviewById找到ID_ANDROID_CONTENT实例
添加自己的View对象。
public void setContentView(View view, ViewGroup.LayoutParams params) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
view.setLayoutParams(params);
final Scene newScene = new Scene(mContentParent, view);
transitionTo(newScene);
} else {
mContentParent.addView(view, params);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}至此放回了decor中需要包含我们自己写的布局viewgroup。至此形成了以下视图结构。
AppCompatActivity的setContentView的过程
调用AppCompatActivity的setContentView方法
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().setContentView(view, params);
}
public AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, this);
}
return mDelegate;
}通过简单工厂方法根据版本创建对应的实例。
public static AppCompatDelegate create(Activity activity, AppCompatCallback callback) {
return create(activity, activity.getWindow(), callback);
}
private static AppCompatDelegate create(Context context, Window window,
AppCompatCallback callback) {
final int sdk = Build.VERSION.SDK_INT;
// 这几个类都是AppCompatDelegate的子类
if (sdk >= 23) {
return new AppCompatDelegateImplV23(context, window, callback);
} else if (sdk >= 14) {
return new AppCompatDelegateImplV14(context, window, callback);
} else if (sdk >= 11) {
return new AppCompatDelegateImplV11(context, window, callback);
} else {
return new AppCompatDelegateImplV7(context, window, callback);
}
}
AppCompatDelegateImplV7是实现了setContentView的具体类
public void setContentView(View v, ViewGroup.LayoutParams lp) {
ensureSubDecor();
ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
contentParent.removeAllViews();
contentParent.addView(v, lp);
mOriginalWindowCallback.onContentChanged();
}根据样式的需要用inflater创建DectorView的实例,在通过android.R.id.content id 找到对应的viewgroup对象添加我们自己的View,然后通知改变。
private void ensureSubDecor() {
if (!mSubDecorInstalled) {
mSubDecor = createSubDecor();
}
}
private ViewGroup createSubDecor() {
TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
ViewGroup subDecor = null;
if (!mWindowNoTitle) {
if (mIsFloating) {
subDecor = (ViewGroup) inflater.inflate(R.layout.abc_dialog_title_material, null);
mHasActionBar = mOverlayActionBar = false;
} else if (mHasActionBar) {
TypedValue outValue = new TypedValue();
mContext.getTheme().resolveAttribute(R.attr.actionBarTheme, outValue, true);
Context themedContext;
if (outValue.resourceId != 0) {
themedContext = new ContextThemeWrapper(mContext, outValue.resourceId);
} else {
themedContext = mContext;
}
subDecor = (ViewGroup) LayoutInflater.from(themedContext).inflate(R.layout.abc_screen_toolbar, null);
mDecorContentParent = (DecorContentParent) subDecor.findViewById(R.id.decor_content_parent);
mDecorContentParent.setWindowCallback(getWindowCallback());
if (mOverlayActionBar) {
mDecorContentParent.initFeature(FEATURE_SUPPORT_ACTION_BAR_OVERLAY);
}
if (mFeatureProgress) {
mDecorContentParent.initFeature(Window.FEATURE_PROGRESS);
}
if (mFeatureIndeterminateProgress) {
mDecorContentParent.initFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
}
}
} else {
if (mOverlayActionMode) {
subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple_overlay_action_mode, null);
} else {
subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null);
}
}
if (mDecorContentParent == null) {
mTitleView = (TextView) subDecor.findViewById(R.id.title);
}
return subDecor;
}
AppCompatActivity 替换view 的过程
在AppCompatActivity的onCreate方法中对LayoutInfalter进行了Factory的初始化。
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);// 如下onCreate方法进行的初始化
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
final AppCompatDelegate delegate = getDelegate();
delegate.installViewFactory();// 在onCreate方法创建时进行的factory的初始化
}
@Override
public void installViewFactory() {
LayoutInflater layoutInflater = LayoutInflater.from(mContext);
if (layoutInflater.getFactory() == null) {
LayoutInflaterCompat.setFactory2(layoutInflater, this); // 该this,为实现factory的oncreteView
} else {
}}
public static void setFactory2(@NonNull LayoutInflater inflater, @NonNull LayoutInflater.Factory2 factory) {
inflater.setFactory2(factory);
}
}然后在该方法中的LayoutInflater的inflate方法进行了替换。
@Override
public void setContentView(int resId) {
ensureSubDecor();
ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
contentParent.removeAllViews();
LayoutInflater.from(mContext).inflate(resId, contentParent);
mAppCompatWindowCallback.getWrapped().onContentChanged();
}
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}这这一块,进行了判断,当 (root != null && attachToRoot) 的时候将创建的View添加到parent中,当 if (root == null || !attachToRoot)的时候直接返回view。所以当第二个参数为空,第三个参数为true的时候,依然返回创建的View。
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
try {
if (TAG_MERGE.equals(name)) {
rInflate(parser, root, inflaterContext, attrs, false);
} else {
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
temp.setLayoutParams(params);
}
}
if (root != null && attachToRoot) {
root.addView(temp, params);
}
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
throw ie;
}
return result;
}
}
View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,boolean ignoreThemeAttr) {
if (name.equals("view")) {
name = attrs.getAttributeValue(null, "class");
}
try {
View view = tryCreateView(parent, name, context, attrs);
return view;
} catch (InflateException e) {
throw e;
}
}在AppCompatActivity中的onCreate方法中,初始花了mFactory2 ,所以在onCreateView方法会调用到AppCompatDelegateImpl类的onCreateView。
public final View tryCreateView(@Nullable View parent, @NonNull String name,View view;
if (mFactory2 != null) { // 是Androidx中适配的factory,
view = mFactory2.onCreateView(parent, name, context, attrs);//
} else if (mFactory != null) { // 系统的factory
view = mFactory.onCreateView(name, context, attrs);
} else {
view = null;
}
return view;
}
public final View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
return createView(parent, name, context, attrs);
}
@Override
public View createView(View parent, final String name, @NonNull Context context,
@NonNull AttributeSet attrs) {
if ((viewInflaterClassName == null)
|| AppCompatViewInflater.class.getName().equals(viewInflaterClassName)) {
mAppCompatViewInflater = new AppCompatViewInflater();
} else {
}
}
return mAppCompatViewInflater.createView(parent, name, context, attrs, inheritContext,IS_PRE_LOLLIPOP, true, VectorEnabledTintResources.shouldBeUsed() );
}在以下的方法中替换成对应的AppCompatXX控件。
final View createView(View parent, final String name, @NonNull Context context, @NonNull AttributeSet attrs, boolean inheritContext,
boolean readAndroidTheme, boolean readAppTheme, boolean wrapContext) {
final Context originalContext = context;
if (inheritContext && parent != null) {
context = parent.getContext();
}
if (readAndroidTheme || readAppTheme) {
context = themifyContext(context, attrs, readAndroidTheme, readAppTheme);
}
if (wrapContext) {
context = TintContextWrapper.wrap(context);
}
View view = null;
switch (name) {
case "TextView":
view = createTextView(context, attrs);
break;
case "ImageView":
view = createImageView(context, attrs);
break;
case "Button":
view = createButton(context, attrs);
break;
case "EditText":
view = createEditText(context, attrs);
break;
case "Spinner":
view = createSpinner(context, attrs);
break;
case "ImageButton":
view = createImageButton(context, attrs);
break;
case "CheckBox":
view = createCheckBox(context, attrs);
break;
case "RadioButton":
view = createRadioButton(context, attrs);
break;
case "CheckedTextView":
view = createCheckedTextView(context, attrs);
break;
case "AutoCompleteTextView":
view = createAutoCompleteTextView(context, attrs);
break;
case "MultiAutoCompleteTextView":
view = createMultiAutoCompleteTextView(context, attrs);
break;
case "RatingBar":
view = createRatingBar(context, attrs);
break;
case "SeekBar":
view = createSeekBar(context, attrs);
break;
case "ToggleButton":
view = createToggleButton(context, attrs);
break;
default:
view = createView(context, name, attrs);
}
if (view == null && originalContext != context) {
view = createViewFromTag(context, name, attrs);// 进行包名的拼接
}
if (view != null) {
checkOnClickListener(view, attrs);
}
return view;
}private static final String[] sClassPrefixList = {
"android.widget.",
"android.view.",
"android.webkit."
}; private View createViewFromTag(Context context, String name, AttributeSet attrs) {
if (name.equals("view")) {
name = attrs.getAttributeValue(null, "class");
} try {
mConstructorArgs[0] = context;
mConstructorArgs[1] = attrs;
if (-1 == name.indexOf('.')) { // 是否是自定义的View
for (int i = 0; i < sClassPrefixList.length; i++) {
final View view = createViewByPrefix(context, name, sClassPrefixList[i]);
if (view != null) {
return view;
}
}
return null;
} else {
return createViewByPrefix(context, name, null);
}
} catch (Exception e) {
return null;
} finally {
mConstructorArgs[0] = null;
mConstructorArgs[1] = null;
}
}
获取到构造方法,进行缓存,constructor.newInstance创建出view,并返回。
private static final Map<String, Constructor<? extends View>> sConstructorMap= new ArrayMap<>(); // 构造方法的缓存,因为反射太过于消耗
private static final Class<?>[] sConstructorSignature = new Class[]{Context.class, AttributeSet.class}; // 构造方法,该参数决定了xml中调用2个参数的构造方法
private View createViewByPrefix(Context context, String name, String prefix)throws ClassNotFoundException, InflateException {
Constructor<? extends View> constructor = sConstructorMap.get(name);
try {
if (constructor == null) {
Class<? extends View> clazz = context.getClassLoader().loadClass(
prefix != null ? (prefix + name) : name).asSubclass(View.class);
constructor = clazz.getConstructor(sConstructorSignature);// 获取类的2个参数的构造方法
sConstructorMap.put(name, constructor);
} constructor.setAccessible(true);
return constructor.newInstance(mConstructorArgs);
} catch (Exception e) {
// We do not want to catch these, lets return null and let the actual LayoutInflater
// try
return null;
}
}
end.