美文网首页
Android 布局的加载

Android 布局的加载

作者: sunjiandev | 来源:发表于2019-11-07 20:34 被阅读0次

Android 布局的加载

此次分析是基于Android sdk 28,看到网络上好多有写的不错的博客,绝大多数都没有说明是基于Android 那个版本来分析,因为随着Android版本的演进,api是有变化的

在开始之前先看一个Actiivty 页面的结构图

image

开始

设置Activity 的布局,是通过 ==AppCompatActivity== 的:

    @Override
    public void setContentView(@LayoutRes int layoutResID) {
        getDelegate().setContentView(layoutResID);
    }

然后看看这个里面 ==setContentView== 是从哪里来的?这是 ==AppCompatDelegate== 这个的一个函数,可以看看这个类是做什么用的

 This class represents a delegate which you can use to extend AppCompat's support to any
 * {@link android.app.Activity}.

翻译过来就是: 此类表示可用于将AppCompat支持扩展到任何Activity的委托。比较拗口,直白点就是这个类支持actiivty 的一些扩展功能,是一个代理类,支持的功能如下:

  • addContentView(android.view.View, android.view.ViewGroup.LayoutParams)
  • setContentView(int)
  • setContentView(android.view.View)
  • setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
  • requestWindowFeature(int)
  • hasWindowFeature(int)
  • invalidateOptionsMenu()
  • startSupportActionMode(android.support.v7.view.ActionMode.Callback)
  • setSupportActionBar(android.support.v7.widget.Toolbar)
  • getSupportActionBar()
  • getMenuInflater()
  • findViewById(int)

其实这部分功能的主要实现还是在window中,只不过是将这部分功能将window与activity 进行隔离,避免耦合

可以对比一下:
以 ==setContentView(viewId)== 为例:

  • android sdk 28:

AppCompatActivity$setContentView

    @Override
    public void setContentView(@LayoutRes int layoutResID) {
     // 拿到AppCompatDelegate的实例,调用函数
       getDelegate().setContentView(layoutResID);
      
    }
  • android sdk 23

Activity$setContentView

  public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

可以看出,同一个方法,android的不同版本是有区别的,在具体看看 ==getDelegate().setContentView(layoutResID);==

AppCompatDelegate是抽像类,具体的实现是AppCompatDelegateImp

AppCompatDelegateImp$setContentView

     @Override
    public void setContentView(int resId) {
        //初始化DecorView
        ensureSubDecor();
        //设置setContentView 要记载的父布局
        ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
        //加载之前移除所有的布局
        contentParent.removeAllViews();
        //完成布局的加载
        LayoutInflater.from(mContext).inflate(resId, contentParent);
        mOriginalWindowCallback.onContentChanged();
    }

然后我们可以看看AppCompatDelegateImp$ensureSubDecor这个函数里面做了什么事:

 private void ensureSubDecor() {
            //默认是false,如果为true的表明 subDecor已经被加载过了
        if (!mSubDecorInstalled) {
        
            mSubDecor = createSubDecor();


            //设置actiivty 的title
            // If a title was set before we installed the decor, propagate it now
            CharSequence title = getTitle();
            if (!TextUtils.isEmpty(title)) {
                if (mDecorContentParent != null) {
                    mDecorContentParent.setWindowTitle(title);
                } else if (peekSupportActionBar() != null) {
                    peekSupportActionBar().setWindowTitle(title);
                } else if (mTitleView != null) {
                    mTitleView.setText(title);
                }
            }

            //为subDecor 设置固定的大小
            applyFixedSizeWindow();

            //空方法
            onSubDecorInstalled(mSubDecor);

            //设置 subDecor 已经被加载过了
            mSubDecorInstalled = true;

            // Invalidate if the panel menu hasn't been created before this.
            // Panel menu invalidation is deferred avoiding application onCreateOptionsMenu
            // being called in the middle of onCreate or similar.
            // A pending invalidation will typically be resolved before the posted message
            // would run normally in order to satisfy instance state restoration.
            PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
            if (!mIsDestroyed && (st == null || st.menu == null)) {
                invalidatePanelMenu(FEATURE_SUPPORT_ACTION_BAR);
            }
        }
    }

然后在看看 ==AppCompatDelegateImp$applyFixedSizeWindow()== 函数

 private void applyFixedSizeWindow() {
        //注意这个控件,它在界面的位置看下面的这张图
        ContentFrameLayout cfl = (ContentFrameLayout) mSubDecor.findViewById(android.R.id.content);

        // This is a bit weird. In the framework, the window sizing attributes control
        // the decor view's size, meaning that any padding is inset for the min/max widths below.
        // We don't control measurement at that level, so we need to workaround it by making sure
        // that the decor view's padding is taken into account.
        
        //获取 DecorView
        final View windowDecor = mWindow.getDecorView();
        
        //设置ContentFrameLayout 布局的间距
        cfl.setDecorPadding(windowDecor.getPaddingLeft(),
                windowDecor.getPaddingTop(), windowDecor.getPaddingRight(),
                windowDecor.getPaddingBottom());

        TypedArray a = mContext.obtainStyledAttributes(R.styleable.AppCompatTheme);
        a.getValue(R.styleable.AppCompatTheme_windowMinWidthMajor, cfl.getMinWidthMajor());
        a.getValue(R.styleable.AppCompatTheme_windowMinWidthMinor, cfl.getMinWidthMinor());

        if (a.hasValue(R.styleable.AppCompatTheme_windowFixedWidthMajor)) {
            a.getValue(R.styleable.AppCompatTheme_windowFixedWidthMajor,
                    cfl.getFixedWidthMajor());
        }
        if (a.hasValue(R.styleable.AppCompatTheme_windowFixedWidthMinor)) {
            a.getValue(R.styleable.AppCompatTheme_windowFixedWidthMinor,
                    cfl.getFixedWidthMinor());
        }
        if (a.hasValue(R.styleable.AppCompatTheme_windowFixedHeightMajor)) {
            a.getValue(R.styleable.AppCompatTheme_windowFixedHeightMajor,
                    cfl.getFixedHeightMajor());
        }
        if (a.hasValue(R.styleable.AppCompatTheme_windowFixedHeightMinor)) {
            a.getValue(R.styleable.AppCompatTheme_windowFixedHeightMinor,
                    cfl.getFixedHeightMinor());
        }
        a.recycle();

        cfl.requestLayout();
    }

说了半天可能还是有点晕,看着张图解明白了:

image

到这里就结束了!

相关文章

网友评论

      本文标题:Android 布局的加载

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