美文网首页
Android源码解析UI绘制流程

Android源码解析UI绘制流程

作者: 滗仙 | 来源:发表于2018-02-11 23:50 被阅读0次

    说到android的UI绘制流程,咱们首先介绍一下setContentView这个大家经常用到的方法。当创建一个Activity时,实现了onCreate方法,然后把创建好的布局Layout或者View通过调用setContentView(xxx)就显示到窗口中了。那么接下来就带着下面的疑问,了解View的加载过程。

    为什么调用了setContentView后就可以显示出我们的局部页面?

    看看源码中setContentView究竟做了什么

        private Window mWindow;
        public void setContentView(@LayoutRes int layoutResID) {
            getWindow().setContentView(layoutResID);
            initWindowDecorActionBar();
        }
        public Window getWindow() {
            return mWindow;
        }
    

    从源码中可以看到setContentView中调用了getWindow方法获取了Window对象,看看源码中对Window对象的定义。

    /**
     * Abstract base class for a top-level window look and behavior policy.  An
     * instance of this class should be used as the top-level view added to the
     * window manager. It provides standard UI policies such as a background, title
     * area, default key processing, etc.
     *
     * <p>The only existing implementation of this abstract class is
     * android.view.PhoneWindow, which you should instantiate when needing a
     * Window.
     */
    public abstract class Window {
            public View findViewById(@IdRes int id) {}
            public void setBackgroundDrawableResource(@DrawableRes int resId) {}
            ...
    
    }
    

    从注释中我们看到Window对象是一个顶层窗口的抽象类,里面封装了一些跟窗口UI相关的方法。既然Window是一个抽象类,那么我们就去看一下它的唯一实现类PhoneWindow。

    public class PhoneWindow extends Window{
        // This is the view in which the window contents are placed. It is either
        // mDecor itself, or a child of mDecor where the contents go.
        private ViewGroup mContentParent;
        // This is the top-level view of the window, containing the window decor.
        private DecorView mDecor;
        @Override
        public void setContentView(int layoutResID) {
            // 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)) {
                final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                        getContext());
                transitionTo(newScene);
            } else {
                mLayoutInflater.inflate(layoutResID, mContentParent);
            }
            ...
        }
    }
    

    PhoneWindow类中的setContentView方法里面用到了mContentParent,它的类型是ViewGroup,从注释中看到我们的Activity中的View就会放到这个ViewGroup中,换而言之就是Window内容要摆放的一个地方,要么是mDecor自己要么就是mDecor的子类。而这个DecorView就是Window最顶层的View。从代码中看到当mContentParent为空时,调用了installDecor方法,进去看一下。

    private void installDecor() {
            if (mDecor == null) {
                //generateDecor方法中new了一个DecorView
                mDecor = generateDecor();
                ...
            }
            if (mContentParent == null) {
                mContentParent = generateLayout(mDecor);
                 ...
               }
        }
    
    protected ViewGroup generateLayout(DecorView decor) {
            ...
            // Inflate the window decor.
            int layoutResource;
            //根据不同的features加载不同的layout布局文件
            int features = getLocalFeatures();
            if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
                ...
            } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
                ...
            } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
                    && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
                ...
            } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
                
            } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
                ...
            } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
                ...
            } else {
                layoutResource = R.layout.screen_simple;
            }
    
            View in = mLayoutInflater.inflate(layoutResource, null);
            decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
            mContentRoot = (ViewGroup) in;
            //代码看到这就可以看出上文提到的mContentParent就是布局
            //layoutResource中id为content的FrameLayout,下文中会接着提到。
            //public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
            ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
           
            return contentParent;
        }
    

    DecorView的结构拿最简单的R.layout.screen_simple为例,如下图:

    image.png

    本文原创,转载请注明出处。

    相关文章

      网友评论

          本文标题:Android源码解析UI绘制流程

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