美文网首页
setContentView的加载流程

setContentView的加载流程

作者: 大盗海洲 | 来源:发表于2019-04-23 18:24 被阅读0次

    参考:
    链接:https://www.jianshu.com/p/e42b638944ae

    image.png

    Activity View 入口

      @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
           setContentView(layoutResID);
        }
    
    

    getWindow()指Window,而window 是个abstract

        /**
         * Set the activity content from a layout resource.  The resource will be
         * inflated, adding all top-level views to the activity.
         *
         * @param layoutResID Resource ID to be inflated.
         *
         * @see #setContentView(android.view.View)
         * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
         */
        public void setContentView(@LayoutRes int layoutResID) {
            getWindow().setContentView(layoutResID);
            initWindowDecorActionBar();
        }
    
    
    

    Window 的创建

    class PhoneWindow extends Window
    有window 的实现类PhoneWindow实例化对象

    
        /**
         * Retrieve the current {@link android.view.Window} for the activity.
         * This can be used to directly access parts of the Window API that
         * are not available through Activity/Screen.
         *
         * @return Window The current window, or null if the activity is not
         *         visual.
         */
        public Window getWindow() {
            return 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) {
        //实例化Window
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
    }
    

    PhoneWindow&setContentView

    如果当前内容还未放置到窗口,此时mContentParent==null,也就是第一次调用的时候,调用那个installDecor方法。FEATURE_CONTENT_TRANSITIONS,则是标记当前内容加载有没有使用过度动画,也就是转场动画。如果内容已经加载过,并且不需要动画,则会调用removeAllViews。添加完Content后如有设置了FEATURE_CONTENT_TRANSITIONS则添加Scene来过度启动。否则mLayoutInflater.inflate(layoutResID, mContentParent);将我们的资源文件通过LayoutInflater对象转换为View树,并且添加至mContentParent视图中。既然是第一次启动则会调用到installDecor,从字面上看可以知道该方法用来添加DecorView,看下里面说明

      // 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) {
                //创建DecorView,并添加到mContentParent上
                installDecor();
            } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
                mContentParent.removeAllViews();
            }
    
            if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
                final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                        getContext());
                transitionTo(newScene);
            } else {
                //将要加载的资源添加到mContentParent上
                mLayoutInflater.inflate(layoutResID, mContentParent);
            }
            mContentParent.requestApplyInsets();
            final Callback cb = getCallback();
            if (cb != null && !isDestroyed()) {
                //回调通知表示完成界面加载
                cb.onContentChanged();
            }
        }
    

    PhoneWindow&installDecor()

        private void installDecor() {
            mForceDecorInstall = false;
            if (mDecor == null) {
                //创建DecorView
                mDecor = generateDecor(-1);
                mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
                mDecor.setIsRootNamespace(true);
                if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                    mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
                }
            } else {
                mDecor.setWindow(this);
            }
            if (mContentParent == null) {
                mContentParent = generateLayout(mDecor);
                }
          }
    

    new DecorView();

      protected DecorView generateDecor(int featureId) {
            //DecorView 为FrameLayout
            return new DecorView(context, featureId, this, getAttributes());
        }
    
    

    generateLayout的返回是contentParent,而它的获取则是ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);`

    public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
    
    protected ViewGroup generateLayout(DecorView decor) {
            ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
            return contentParent;
        }
    

    PhoneWindow&setContentView(view)

      @Override
        public void setContentView(View view) {
            setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        }
    
    
    
        @Override
        public void setContentView(View view, ViewGroup.LayoutParams params) {
           if (mContentParent == null) {
                installDecor();
            }
               //addView()
                mContentParent.addView(view, params);
    
            final Callback cb = getCallback();
            if (cb != null && !isDestroyed()) {
               //回调通知表示完成界面改变
                cb.onContentChanged();
            }
        }
    

    小结

    • Window是一个抽象类,提供了各种窗口操作的方法,比如设置背景标题ContentView等等
    • PhoneWindow则是Window的唯一实现类,它里面实现了各种添加背景主题ContentView的方法,内部通过DecorView来添加顶级视图
    • 每一个Activity上面都有一个Window,可以通过getWindow获取
    • DecorView,顶级视图,继承与FramentLayout,setContentView则是添加在它里面的@id/content里
    • setContentView里面创建了DecorView,根据Theme,Feature添加了对应的布局文件
    • 当setContentView设置显示后会回调Activity的onContentChanged方法
    1.setContentView(layoutResID)
     installDecor()--->generateDecor()--->new DecorView()--->FrameLayout
          generateLayout(mDecor)--->contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
                mLayoutInflater.inflate(layoutResID, mContentParent);
    2.setContentView(view)
        setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
             installDecor()--->generateDecor()--->new DecorView()--->FrameLayout
                  generateLayout(mDecor)--->contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
                                mContentParent.addView(view, params);
    
    image.png

    相关文章

      网友评论

          本文标题:setContentView的加载流程

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