美文网首页
setContentView流程分析

setContentView流程分析

作者: 壹元伍角叁分 | 来源:发表于2021-09-13 23:11 被阅读0次

    1、Activity的setContentView加载逻辑

    --> Activity.setContentView(@LayoutRes int layoutResID)
       //getWindow()就是PhoneWindow(在attach()中被创建)。
       --> getWindow().setContentView(layoutResID);
          //创建 DecorView 拿到 Content--------------------------top-----------------------
          --> installDecor();
              --> mDecor = generateDecor(-1);
                 --> return new DecorView(context, featureId, this, getAttributes());
              --> mContentParent = generateLayout(mDecor);
                  //根据用户配置,加载layout,下面以R.layout.screen_simple为例
                  --> layoutResource = R.layout.screen_simple;
                      --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                            android:layout_width="match_parent"
                            android:layout_height="match_parent"
                            android:fitsSystemWindows="true"
                            android:orientation="vertical">
                               <ViewStub android:id="@+id/action_mode_bar_stub"
                                  android:inflatedId="@+id/action_mode_bar"
                                  android:layout="@layout/action_mode_bar"
                                  android:layout_width="match_parent"
                                  android:layout_height="wrap_content"
                                  android:theme="?attr/actionBarTheme" />
                               <FrameLayout
                                  android:id="@android:id/content"
                                  android:layout_width="match_parent"
                                  android:layout_height="match_parent"
                                  android:foregroundInsidePadding="false"
                                  android:foregroundGravity="fill_horizontal|top"
                                  android:foreground="?android:attr/windowContentOverlay" />
                          </LinearLayout>
                  --> mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
                     --> final View root = inflater.inflate(layoutResource, null);
                         --> return inflate(resource, root, root != null);
                            --> XmlResourceParser parser = res.getLayout(resource);
                            --> return inflate(parser, root, attachToRoot);
                               //加载merge为根节点的view
                               --> rInflate(parser, root, inflaterContext, attrs, false);
                               //加载非merge根节点的view
                               --> final View temp = createViewFromTag(root, name, inflaterContext, attrs);
                                  --> return createViewFromTag(parent, name, context, attrs, false);
                                      --> View view = tryCreateView(parent, name, context, attrs);
                                           //加载sdk中的view
                                      -->  if (-1 == name.indexOf('.')) {
                                               view = onCreateView(context, parent, name, attrs);
                                               --> return onCreateView(parent, name, attrs);
                                                  --> return onCreateView(name, attrs);
                                                     --> return createView(name, "android.view.", attrs);//拼接完整类名
                                                        -->  return createView(context, name, prefix, attrs);
                                                           //通过反射创建View  --- 布局的rootView
                                                           --> clazz = Class.forName(prefix != null ? (prefix + name) : name, false
                                                                        ,mContext.getClassLoader()).asSubclass(View.class);
                                                           --> final View view = constructor.newInstance(args);
                                           } else {
                                               //加载自定义view
                                               view = createView(context, name, null, attrs);
                                                 --> clazz = Class.forName(prefix != null ? (prefix + name) : name, false
                                                            ,mContext.getClassLoader()).asSubclass(View.class);
                                                 --> final View view = constructor.newInstance(args);
                                           }
                               //加载非merge根节点副节点的子view
                               --> rInflateChildren(parser, temp, attrs, true);
                                   --> rInflate(parser, parent, parent.getContext(), attrs, finishInflate);
                     --> addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
                  //找到ID_ANDROID_CONTENT = com.android.internal.R.id.content的view
                  --> ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
                  //返回contentView
                  --> return contentParent;
          //创建 DecorView 拿到 Content-------------------------bottom---------------------
          //将R.layout.activity_main 渲染到 mContentParent
          --> mLayoutInflater.inflate(layoutResID, mContentParent);
          //调用setContentView方法后,会设置一个标志位,这也就是为什么在setContentView()调用requestFeature()会崩溃的原因。
          --> mContentParentExplicitlySet = true;
    

    2、AppCompatActivity的setContentView加载逻辑

    --> AppCompatActivity.setContentView(@LayoutRes int resId)
        //getDelegate()就是AppCompatDelegate,AppCompatDelegate是个接口,找到它的实现类AppCompatDelegateImpl
        --> getDelegate().setContentView(resId);
            --> ensureSubDecor();
                --> mSubDecor = createSubDecor();
                    --> mWindow.getDecorView();
                        //走到phoneWindow的getDecorView(),这个里面就和上面activity的逻辑一样了.......
                        //加载R.layout.screen_simple,
                        --> installDecor();
                    //根据用户配置,加载layout,下面以R.layout.abc_screen_simple为例
                    --> subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null);
                        --> <androidx.appcompat.widget.FitWindowsLinearLayout
                              xmlns:android="http://schemas.android.com/apk/res/android"
                              android:id="@+id/action_bar_root"
                              android:layout_width="match_parent"
                              android:layout_height="match_parent"
                              android:orientation="vertical"
                              android:fitsSystemWindows="true">
                              <androidx.appcompat.widget.ViewStubCompat
                                android:id="@+id/action_mode_bar_stub"
                                android:inflatedId="@+id/action_mode_bar"
                                android:layout="@layout/abc_action_mode_bar"
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content" />
                              <include layout="@layout/abc_screen_content_include" />
                                --> <merge xmlns:android="http://schemas.android.com/apk/res/android">
                                      <androidx.appcompat.widget.ContentFrameLayout
                                      android:id="@id/action_bar_activity_content" //把这个view的id重新设置为android.R.id.content
                                      android:layout_width="match_parent"
                                      android:layout_height="match_parent"
                                      android:foregroundGravity="fill_horizontal|top"
                                      android:foreground="?android:attr/windowContentOverlay" />
                                    </merge>
                            </androidx.appcompat.widget.FitWindowsLinearLayout>
                    //找到action_bar_activity_content的view
                    --> final ContentFrameLayout contentView = (ContentFrameLayout) subDecor.findViewById(
                      R.id.action_bar_activity_content);
                    //找到android.R.id.content的view
                    --> final ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content);
                    //将R.layout.abc_screen_simple中的android.R.id.content的id设置为:NO_ID = -1
                    --> windowContentView.setId(View.NO_ID);
                    //设置之前id为action_bar_activity_content的view 的id 为android.R.id.content
                    --> contentView.setId(android.R.id.content);
                    --> mWindow.setContentView(subDecor);
                        --> setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
                            //把
                            --> mContentParent.addView(view, params);
    
            //找到R.id.content的view
            --> ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
            //R.layout.activity_main View 创建,这个逻辑跟上面activity的逻辑一样了.......
            --> LayoutInflater.from(mContext).inflate(resId, contentParent);
    

    示意图:


    Activity.jpg AppCompatActivity.jpg

    相关文章

      网友评论

          本文标题:setContentView流程分析

          本文链接:https://www.haomeiwen.com/subject/ddeqgltx.html