setContentView源码解析 总结一下代码逻辑: 1 Activity的PhoneWindow属性创建DecorView contentParent 2 LayoutInflater解析XML文件遍历子view创建根节点(也就是我们的contentView) 为了方便我把代码分成两个阶段 到此为止我们知道Activity里面的Window其实就是PhoneWindow,每创建一个Activity其实就新建一个PhoneWindow对象 所以AppCompatDelegateImpl.java对mWindow的操作其实就是对PhoneWindow的操作。 这两个方法都要调用installDecor(),这是用来干嘛的呢?是来创建DecorView和ContentView的 现在我们确定了一点,mFactory2在MainActivity.java中的super.onCreate(savedInstanceState)就获得了初始化。mFactory2就是AppCompatDelegateImpl实例化对象,下面回到4.4 LayoutInflater.java代码中继续分析 这就是为啥你XML布局即使写成TextView但是使用的时候发现也是AppcompatTextView的原因,系统自动帮你做了转换处理,最终返回了一个View.我们已经知道根节点的view是如何生成的了但是子节点是怎么创建出来的呢? 大致就到这里啦,至于Activity的setContentView创建过程基本和AppcompatActivity一样,只是Activity使用的是反射,AppcompatActivity做了一层包装(XXXView包装成AppcompaXXX)文章目录
1 MainActivity.java
public class MainActivity extends AppCompatActivity { public static final String TAG = "_MainActivity_"; private TextView mTv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //我们研究的就是这个setContentView setContentView(R.layout.activity_main); mTv = findViewById(R.id.tv); } }
2 AppCompatActivity.java
@Override public void setContentView(@LayoutRes int layoutResID) { getDelegate().setContentView(layoutResID); } @NonNull public AppCompatDelegate getDelegate() { if (mDelegate == null) { mDelegate = AppCompatDelegate.create(this, this); } return mDelegate; }
3 AppCompatDelegate.java
@NonNull public static AppCompatDelegate create(@NonNull Activity activity, @Nullable AppCompatCallback callback) { return new AppCompatDelegateImpl(activity, callback); } public abstract void setContentView(@LayoutRes int resId);
4 AppCompatDelegateImpl.java
@Override public void setContentView(int resId) { //确保decorView和ContentView存在,如果不存在就创建它 --->第一阶段 ensureSubDecor(); //可以看出来android.R.id.content就是我们的contentView的id ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content); contentParent.removeAllViews(); //contentView根布局清除完之后才可以填充视图 ---->第二阶段 LayoutInflater.from(mContext).inflate(resId, contentParent); mAppCompatWindowCallback.getWrapped().onContentChanged(); }
第一阶段
private void ensureSubDecor() { if (!mSubDecorInstalled) { //检查你的Appcompat属性是否存在,按照你的主题属性来配置Activity mSubDecor = createSubDecor(); ...... } } private ViewGroup createSubDecor() { TypedArray a = mContext.obtainStyledAttributes(R.styleable.AppCompatTheme); //下面这句太熟悉了,每次我们主题设置设置错误或者没有设置主题就会报错 if (!a.hasValue(R.styleable.AppCompatTheme_windowActionBar)) { a.recycle(); throw new IllegalStateException( "You need to use a Theme.AppCompat theme (or descendant) with this activity."); } //下面就是根据你的主题属性来配置Activity if (a.getBoolean(R.styleable.AppCompatTheme_windowNoTitle, false)) { requestWindowFeature(Window.FEATURE_NO_TITLE); } else if (a.getBoolean(R.styleable.AppCompatTheme_windowActionBar, false)) { // Don't allow an action bar if there is no title. requestWindowFeature(FEATURE_SUPPORT_ACTION_BAR); } if (a.getBoolean(R.styleable.AppCompatTheme_windowActionBarOverlay, false)) { requestWindowFeature(FEATURE_SUPPORT_ACTION_BAR_OVERLAY); } if (a.getBoolean(R.styleable.AppCompatTheme_windowActionModeOverlay, false)) { requestWindowFeature(FEATURE_ACTION_MODE_OVERLAY); } mIsFloating = a.getBoolean(R.styleable.AppCompatTheme_android_windowIsFloating, false); a.recycle(); //下面这两行很重要,涉及到和Window的绑定了 //所以我们要首先知道这个mWindow到底是什么? ensureWindow(); mWindow.getDecorView(); //代码见 4.3PhoneWindow.java ... mWindow.setContentView(subDecor);//代码见 4.3PhoneWindow.java ..... } private void ensureWindow() { ... if (mWindow == null && mHost instanceof Activity) { //(Activity) mHost).getWindow()又是什么鬼? attachToWindow(((Activity) mHost).getWindow()); } ... } private void attachToWindow(@NonNull Window window) { ... //当前mWindow在此处被唯一赋值,值就是(Activity) mHost).getWindow() mWindow = window; }
4.1 Activity.java
public Window getWindow() { return mWindow; } //mWindow又在哪里被赋值了呢? final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) { ... attachBaseContext(context); mWindow = new PhoneWindow(this, window, activityConfigCallback); //这句话后面会提到 mWindow.getLayoutInflater().setPrivateFactory(this); ... } //这里的attach方法在哪里被调用了呢?其实就是Activity启动过程中发生的, 代码在ActivityThread.java类
4.2 ActivityThread.java
ActivityThread.java private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ... //注意这里的outerContext是Activity appContext.setOuterContext(activity); activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.configCallback, r.assistToken); ... }
4.3 PhoneWindow.java
@Override public final @NonNull View getDecorView() { if (mDecor == null || mForceDecorInstall) { installDecor(); } return mDecor; } @Override public void setContentView(int layoutResID) { if (mContentParent == null) { installDecor(); } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); } ... }
private void installDecor() { mForceDecorInstall = false; if (mDecor == null) { //生成DecorView mDecor = generateDecor(-1); ... } else { mDecor.setWindow(this); } if (mContentParent == null) { //生成mContentParent mContentParent = generateLayout(mDecor); ... } { protected DecorView generateDecor(int featureId) { ... //说明一个PhoneWindow也是创建一个DecorView return new DecorView(context, featureId, this, getAttributes()); } protected ViewGroup generateLayout(DecorView decor) { ... //去找布局中的ID_ANDROID_CONTENT控件 ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); ... return contentParent; }
第二阶段
@Override public void setContentView(int resId) { //确保decorView和ContentView存在,如果不存在就创建它 --->第一阶段 ensureSubDecor(); //可以看出来android.R.id.content就是我们的contentView的id ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content); contentParent.removeAllViews(); //其实这里相当于PhoneWindow暴露出一个对象供需要填充view的类使用 //contentView根布局清除完之后才可以填充视图 ---->第二阶段 LayoutInflater.from(mContext).inflate(resId, contentParent); mAppCompatWindowCallback.getWrapped().onContentChanged(); }
4.4 LayoutInflater.java
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) { .... //开始解析我们写的XML文件了 XmlResourceParser parser = res.getLayout(resource); try { return inflate(parser, root, attachToRoot); } finally { parser.close(); } .... }
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) { ... //先去找root节点 final View temp = createViewFromTag(root, name, inflaterContext, attrs); // 解析子view rInflateChildren(parser, temp, attrs, true); //将所有的节点添加到view树上 if (root != null && attachToRoot) { root.addView(temp, params); } }
private View createViewFromTag(View parent, String name, Context context, AttributeSet attrs) { return createViewFromTag(parent, name, context, attrs, false); }
View createViewFromTag(View parent, String name, Context context, AttributeSet attrs, boolean ignoreThemeAttr) { ... //父类是 AppcompatActivity根据view名称new一个对象出来。 View view = tryCreateView(parent, name, context, attrs); //父类是 Activity 或者是自定义的的View 则反射生成一个view if (view == null) { final Object lastContext = mConstructorArgs[0]; mConstructorArgs[0] = context; try { if (-1 == name.indexOf('.')) { view = onCreateView(context, parent, name, attrs); } else { view = createView(context, name, null, attrs); } } finally { mConstructorArgs[0] = lastContext; } } ... }
public final View tryCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs) { if (name.equals(TAG_1995)) { // Let's party like it's 1995! return new BlinkLayout(context, attrs); } //一脸懵逼mFactory2是什么?mFactor是什么?mPrivateFactor又是什么? //首先是mFactory2尝试加载view,如果mFactory为空才会使用mFactory加载 //如果两者都为空或者两者创建的view都是空,就会尝试让mPrivateFactory创建一下 View view; 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) { // 4.1 Activity.java mWindow.getLayoutInflater().setPrivateFactory(this); // mPrivateFactory其实就是Activity,所以在这里就是调用Activity的onCreateView view = mPrivateFactory.onCreateView(parent, name, context, attrs); } return view; }
4.5 Activity.java —> mPrivateFactory
@Nullable public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs) { if (!"fragment".equals(name)) { //这个name就是view的名字,我们平时声明的都是TextView/Button等等 return onCreateView(name, context, attrs); } //所以知道为啥我们要使用<fragment>而不是<Fragment>创建fragment节点了吧 //只有fragment才会被检测到,通过碎片控制器生成碎片 return mFragments.onCreateView(parent, name, context, attrs); } @Nullable public View onCreateView(@NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs) { //Activity只负责fragment的创建,其他view一律不管 return null; } //这里就把mPrivateFactory讲完了,我们看下另外两个mFactory和mFactory2
4.6 LayoutInflater.java
//先找到这几个变量定义的地方 @UnsupportedAppUsage private Factory mFactory; @UnsupportedAppUsage private Factory2 mFactory2; //查询了赋值的操作,共有三处 protected LayoutInflater(LayoutInflater original, Context newContext) { ... mFactory = original.mFactory; mFactory2 = original.mFactory2; mPrivateFactory = original.mPrivateFactory; ... } public void setFactory(Factory factory) { ... mFactorySet = true; if (mFactory == null) { mFactory = factory; } else { mFactory = new FactoryMerger(factory, null, mFactory, mFactory2); } } //层层寻找调用此方法的地方,接下来逻辑是倒过来的 调用链从顺序变为倒序 public void setFactory2(Factory2 factory) { ... mFactorySet = true; if (mFactory == null) { mFactory = mFactory2 = factory; } else { mFactory = mFactory2 = new FactoryMerger(factory, factory, mFactory, mFactory2); } }
4.7 LayoutInflaterCompat.java
public static void setFactory2( @NonNull LayoutInflater inflater, @NonNull LayoutInflater.Factory2 factory) { inflater.setFactory2(factory); if (Build.VERSION.SDK_INT < 21) { final LayoutInflater.Factory f = inflater.getFactory(); if (f instanceof LayoutInflater.Factory2) { // The merged factory is now set to getFactory(), but not getFactory2() (pre-v21). // We will now try and force set the merged factory to mFactory2 forceSetFactory2(inflater, (LayoutInflater.Factory2) f); } else { // Else, we will force set the original wrapped Factory2 forceSetFactory2(inflater, factory); } } }
4.8 AppCompatDelegateImpl.java
@Override public void installViewFactory() { LayoutInflater layoutInflater = LayoutInflater.from(mContext); if (layoutInflater.getFactory() == null) { //传了参数this,说明mFactory2就是AppCompatDelegateImpl实例 LayoutInflaterCompat.setFactory2(layoutInflater, this); } else { if (!(layoutInflater.getFactory2() instanceof AppCompatDelegateImpl)) { Log.i(TAG, "The Activity's LayoutInflater already has a Factory installed" + " so we can not install AppCompat's"); } } }
4.9 AppCompatActivity.java
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { final AppCompatDelegate delegate = getDelegate(); //在这里进行installViewFactory delegate.installViewFactory(); delegate.onCreate(savedInstanceState); super.onCreate(savedInstanceState); }
4.10 MainActivity.java
@Override protected void onCreate(Bundle savedInstanceState) { //父类去执行了注册mFatory2的工作 super.onCreate(savedInstanceState); }
View view; if (mFactory2 != null) { //这里mFactory2就是AppCompatDelegateImpl view = mFactory2.onCreateView(parent, name, context, attrs); } else if (mFactory != null) { view = mFactory.onCreateView(name, context, attrs); } else { view = null; }
Back 4 AppCompatDelegateImpl.java
@Override 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) { ... //创建了一个AppCompatViewInflater来解析View mAppCompatViewInflater = new AppCompatViewInflater(); return mAppCompatViewInflater.createView(parent, name, context, attrs, inheritContext, IS_PRE_LOLLIPOP, /* Only read android:theme pre-L (L+ handles this anyway) */ true, /* Read read app:theme as a fallback at all times for legacy reasons */ VectorEnabledTintResources.shouldBeUsed() /* Only tint wrap the context if enabled */ ); }
5 AppCompatViewInflater.java
final View createView(View parent, final String name, @NonNull Context context, @NonNull AttributeSet attrs, boolean inheritContext, boolean readAndroidTheme, boolean readAppTheme, boolean wrapContext) { switch (name) { case "TextView": view = createTextView(context, attrs); verifyNotNull(view, name); break; case "ImageView": view = createImageView(context, attrs); verifyNotNull(view, name); break; case "Button": view = createButton(context, attrs); verifyNotNull(view, name); break; case "EditText": view = createEditText(context, attrs); verifyNotNull(view, name); break; case "Spinner": view = createSpinner(context, attrs); verifyNotNull(view, name); break; case "ImageButton": view = createImageButton(context, attrs); verifyNotNull(view, name); break; case "CheckBox": view = createCheckBox(context, attrs); verifyNotNull(view, name); break; case "RadioButton": view = createRadioButton(context, attrs); verifyNotNull(view, name); break; case "CheckedTextView": view = createCheckedTextView(context, attrs); verifyNotNull(view, name); break; case "AutoCompleteTextView": view = createAutoCompleteTextView(context, attrs); verifyNotNull(view, name); break; case "MultiAutoCompleteTextView": view = createMultiAutoCompleteTextView(context, attrs); verifyNotNull(view, name); break; case "RatingBar": view = createRatingBar(context, attrs); verifyNotNull(view, name); break; case "SeekBar": view = createSeekBar(context, attrs); verifyNotNull(view, name); break; default: // The fallback that allows extending class to take over view inflation // for other tags. Note that we don't check that the result is not-null. // That allows the custom inflater path to fall back on the default one // later in this method. view = createView(context, name, attrs); } @NonNull protected AppCompatTextView createTextView(Context context, AttributeSet attrs) { return new AppCompatTextView(context, attrs); } @NonNull protected AppCompatImageView createImageView(Context context, AttributeSet attrs) { return new AppCompatImageView(context, attrs); } @NonNull protected AppCompatButton createButton(Context context, AttributeSet attrs) { return new AppCompatButton(context, attrs); } @NonNull protected AppCompatEditText createEditText(Context context, AttributeSet attrs) { return new AppCompatEditText(context, attrs); } @NonNull protected AppCompatSpinner createSpinner(Context context, AttributeSet attrs) { return new AppCompatSpinner(context, attrs); } @NonNull protected AppCompatImageButton createImageButton(Context context, AttributeSet attrs) { return new AppCompatImageButton(context, attrs); }
6 LayoutInflater.java
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) { ... //先去找root节点 final View temp = createViewFromTag(root, name, inflaterContext, attrs); // 解析子view,重点是这里! rInflateChildren(parser, temp, attrs, true); //将根节点附加在contentParent上 if (root != null && attachToRoot) { root.addView(temp, params); } } final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException { rInflate(parser, parent, parent.getContext(), attrs, finishInflate); } void rInflate(XmlPullParser parser, View parent, Context context, AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException { final int depth = parser.getDepth(); int type; boolean pendingRequestFocus = false; while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { if (type != XmlPullParser.START_TAG) { continue; } final String name = parser.getName(); if (TAG_REQUEST_FOCUS.equals(name)) { pendingRequestFocus = true; consumeChildElements(parser); } else if (TAG_TAG.equals(name)) { parseViewTag(parser, parent, attrs); } else if (TAG_INCLUDE.equals(name)) { if (parser.getDepth() == 0) { throw new InflateException("<include /> cannot be the root element"); } parseInclude(parser, context, parent, attrs); } else if (TAG_MERGE.equals(name)) { throw new InflateException("<merge /> must be the root element"); } else { //又开始新一轮的遍历了 final View view = createViewFromTag(parent, name, context, attrs); final ViewGroup viewGroup = (ViewGroup) parent; final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs); rInflateChildren(parser, view, attrs, true); viewGroup.addView(view, params); } } if (pendingRequestFocus) { parent.restoreDefaultFocus(); } if (finishInflate) { parent.onFinishInflate(); } }
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算