文读懂 View 的 Measure、Layout、Draw 流程

美团App 插件化实践 ---https://tech.meituan.com/2017/10/12/android-hydra.html

这个思路是对的,但是远不够。例如,Google 自己的Support包里面的一个类 
android.support.v7.view.ContextThemeWrapper会生成一个新的Theme保存:
ContextThemeWrapper会生成一个新的Theme保存: Theme()

ContextThemeWrapper会生成一个新的Theme保存:


public class ContextThemeWrapper extends ContextWrapper {
    private int mThemeResource;
    private Resources.Theme mTheme;
    private LayoutInflater mInflater;
    ...
    private void initializeTheme() {
        final boolean first = mTheme == null;
        if (first) {
            mTheme = getResources().newTheme();
            final Resources.Theme theme = getBaseContext().getTheme();
            if (theme != null) {
                mTheme.setTo(theme);
            }
        }
        onApplyThemeResource(mTheme, mThemeResource, first);
    }
    ...
}


getBaseContext.getTheme  

  pruneSupportContextThemeWrapper((ContextThemeWrapper) context, newAssetManager); // 清理Theme
  
  pruneSupportContextThemeWrapper ContextThemeWrapper context,newAssetManager
  
  
  ,对应的虚拟机的指令是PUTFIELD/PUTSTATIC,以此为突破口,用ASM写一个MethodVisitor:
  
  PUTSTATIC,以此为突破口,用ASM写一个MethodVisitor: ASM  MethodVistor
  
  static class MyMethodVisitor extends MethodVisitor {
  static class MyMethodVisitor extends MethodVisitor {
  
  }
  
  MethodVisitor
  
   我们将正常构建过程分为4个阶段: 1. 收集依赖 2. 处理资源 3. 处理代码 4. 打包签名
   
  收集依赖  处理资源  处理代码  
   
  
宿主解析依赖之后,分析插件的依赖,进行依赖仲裁和引用计数分析
宿主处理资源之前,处理插件资源,规避了资源访问的陷阱,生成需要Merge的资源列表给宿主,开发 美团AAPT 处理插件资源
宿主处理代码之中,规避插件API使用的陷阱,复用宿主的Proguard和Gradle插件,做到对原生构建过程的最大兼容。我们也修复了Proguard Mapping的问题,后续会有专门的博客介绍
宿主打包签名之前,构建插件APK,计算升级兼容的Hash特征,使用V2签名加快运行时的验证
构建系统的流程如下图

宿主  插件  Merge   AAPT() Merge AAPT   API 是的呢 我们也修复了Proguard Proguard

Merge AAPT                                    

  美团App 插件化实践 ---https://tech.meituan.com/2017/10/12/android-hydra.html
  
  
  宿主处理代码之中,规避插件API使用的陷阱,复用宿主的Proguard和Gradle插件,
  
  做到对原生构建过程的最大兼容。我们也修复了Proguard Mapping的问题,后续会有专门的博客介绍
  
  Proguard Gradle
  
  宿主处理代码之中,规避插件API使用的陷阱,复用宿主的Proguard和Gradle插件,做到对原生构建过程的最大兼容。
  
  我们也修复了Proguard Mapping的问题,后续会有专门的博客介绍        Proguard Mapping的问题,后续会有专门的博客介绍
  
  
  陷阱,生成需要Merge的资源列表给宿主,开发 美团AAPT 处理插件资源        Merge AAPT
  
  
  ,生成需要Merge的资源列表给宿主,开发 美团AAPT 处理插件资源
  
  宿主打包签名之前,构建插件APK,计算升级兼容的Hash特征,使用V2签名加快运行时的验证
  
  宿主打包签名之前,构建插件APK,计算升级兼容的Hash特征,使用V2签名加快运行时的验证
  
  keytool -importkeystore -srckeystore office -destkeystore office -deststoretype pkcs12
  
  keytool -importkeystore -srckeystore D:\office\OfficeHorizontal\offices.jks -destkeystore D:\office\OfficeHorizontal\offices.jks -deststoretype pkcs12
  
  
  https://blog.csdn.net/u012551120/article/details/106670917 ---- Android横竖屏切换,列表中item布局复用错乱
  
  
    美团App 插件化实践 ---https://tech.meituan.com/2017/10/12/android-hydra.html
  
  1. 收集依赖 2. 处理资源 3. 处理代码 4. 打包签名
  
  
  为4个阶段: 1. 收集依赖 2. 处理资源 3. 处理代码 4. 打包签名
  
  1,2,3,4,收集依赖 处理资源 处理代码  打包签名
  
  1,
  
  
  宿主解析依赖之后,分析插件的依赖,进行依赖仲裁和引用计数分析
宿主处理资源之前,处理插件资源,规避了资源访问的陷阱,生成需要Merge的资源列表给宿主,开发 美团AAPT 处理插件资源
宿主处理代码之中,规避插件API使用的陷阱,复用宿主的Proguard和Gradle插件,做到对原生构建过程的最大兼容。
我们也修复了Proguard Mapping的问题,后续会有专门的博客介绍
宿主打包签名之前,构建插件APK,计算升级兼容的Hash特征,使用V2签名加快运行时的验证


Proguard Mapping的问题,后续会有专门的博客介绍 Hash 

Proguard Mapping的问题,后续会有专门的博客介绍 Hash

宿主处理资源之前,处理插件资源,规避了资源访问的陷阱,生成需要Merge的资源列表给宿主,开发

Proguard Gradle

生成需要Merge的资源列表给宿主,开发 美团AAPT 处理插件资源

Merge AAPT  Merge  Merge AAPT 

Merge  AAPT Merge Merge AAPT          
  
  super.visitMethodInsn        
  
    super.visitMethodInsn(Opcodes.INVOKESTATIC,
                        "com/meituan/hydra/runtime/Transformer",//
                        "collectTheme",
                        "(Landroid/content/res/Resources$Theme;)V",
                        false);
                        
                        super.visitMethodInsn Opcodes.INVOKESTATIC,
                        
                        Opcodes.INVOKESTATIC
                        
  
  宿主打包签名之前,构建插件APK,计算升级兼容的Hash特征,使用V2签名加快运行时的验证
  
  宿主打包签名之前,构建插件APK,计算升级兼容的Hash特征,使用V2签名加快运行时的验证
  
  800        7 * 5 = 3500 - 800 = 
  
   美团App 插件化实践 ---https://tech.meituan.com/2017/10/12/android-hydra.html
                    
  亲测Unknown host mirrors.opencas.cn You may need to adjust the proxy settings in Gradle 解决办法 ---https://blog.csdn.net/GodnessIsMyMine/article/details/106517777
  
  
  https://www.jianshu.com/p/20b1c14e048f ----Android dialog 去掉状态栏全屏显示

  https://www.cnblogs.com/Owen-ET/p/10868620.html --- 【Github】之突然访问不了Github地址 
  
  https://run.mockplus.cn/exLeIPdGZAZraFke/index.html
  
  为了实现在AAR集成方式和插件集成方式之间一键切换
  
  AAR 集成方式 和插件 
  
  我们将正常构建过程分为4个阶段: 
  
  1. 收集依赖 2. 处理资源 3. 处理代码 4. 打包签名
  1,收集依赖  2,处理资源  3,处理代码 ,4,打包签名
  
  
  
  宿主解析依赖之后,分析插件的依赖,进行依赖仲裁和引用计数分析
  
宿主处理资源之前,处理插件资源,规避了资源访问的陷阱,生成需要Merge的资源列表给宿主,
开发 美团AAPT 处理插件资源

宿主处理代码之中,规避插件API使用的陷阱,复用宿主的Proguard和Gradle插件,
做到对原生构建过程的最大兼容。我们也修复了Proguard Mapping的问题,后续会有专门的博客介绍

宿主打包签名之前,构建插件APK,计算升级兼容的Hash特征,使用V2签名加快运行时的验证

宿主打包签名之前,构建插件APK,计算升级兼容的Hash特征,使用V2签名加快运行时的验证

Proguard( Gradle) -> Hash()特性

  
  宿主处理资源之前,处理插件资源,规避了资源访问的陷阱,生成需要Merge的资源列表给宿主,开发 美团AAPT 处理插件资源
  
  Merge是啥意思
  
  android merge的作用,Android Merge详解 ---https://blog.csdn.net/weixin_29582621/article/details/117278372
  
  启动 tools> hierarchyviewer.bat工具查看当前UI结构视图:
  tools->hierarchyviewer.bat工具查看当前UI结构视图:
  
  tools->hierarchyviewer.bat工具查看当前UI结构视图:
  
  PhoneWindow DecorView
  
  http://www.javashuo.com/article/p-ktkcxayq-kz.html ---  Android Merge详解
  
  https://www.jianshu.com/p/f1dbcf66b9e1  ----  android UI布局优化之merge标签
  
  
  // 继承RelativeLayout
public class RadioPalyerHistoryView extends RelativeLayout {

    public RadioPalyerHistoryView(@NonNull Context context) {
        this(context, null);
    }

    public RadioPalyerHistoryView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RadioPalyerHistoryView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
       // 必须attachToRoot为true
        View view = LayoutInflater.from(context).inflate(R.layout.radio_palyer_history_right_layout, this, true);
// 跟布局是merge标签,在跟布局设置的padding不管用了,代码设置
 setPadding(CommonUtils.dip2px(context,12),CommonUtils.dip2px(context,10),CommonUtils.dip2px(context,12),CommonUtils.dip2px(context,10));
    }
  
  
  RadioPalyerHistoryView(context,attrs)-> defStyleAttr,CommonUtils,AttributeSet
  attchToRoot = true
  
  // 跟布局是merge标签,在跟布局设置的padding不管用了,代码设置
  
  根布局 merge的作用 = true attchToRoot = true
  
  在LayoutInflater的inflate方法中, 
  
  public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) { 
  XmlPullParser
        synchronized (mConstructorArgs) {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
            //Trace.traceBegin Trace.TRACE_TAG_VIEW,inflate

            final Context inflaterContext = mContext;
            final AttributeSet attrs = Xml.asAttributeSet(parser);
            
            Context lastContext = (Context) mConstructorArgs[0];
            mConstructorArgs[0] = inflaterContext;
            View result = root;

            try {
            // 省略
                ...
                // merge标签必须有root,attachToRoot为true
                merge -> root ,attachToRoot = A903
                if (TAG_MERGE.equals(name)) {
                    if (root == null || !attachToRoot) {
                        throw new InflateException(" can be used only with a valid "
                                + "ViewGroup root and attachToRoot=true");
                    }

                    rInflate(parser, root, inflaterContext, attrs, false);
                } else {
                   ... 

            } catch (XmlPullParserException e) {
            ...

            return result;
        }
    }
    
    
    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(" cannot be the root element");
                }
                parseInclude(parser, context, parent, attrs);
                parseInclude parser,context,parent,attrs
            } else if (TAG_MERGE.equals(name)) {
                throw new InflateException(" must be the root element");
            } else {
                。 没有用merge标签的宽高属性,padding属性,直接addview到parent中
                final View view = createViewFromTag(parent, name, context, attrs);
                //createViewFromTag(parent,name,context,attrs);
                final ViewGroup viewGroup = (ViewGroup) parent;
                final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
                viewGroup.generateLayoutParams
                rInflateChildren(parser, view, attrs, true);
                viewGroup.addView(view, params);
                viewGroup.addView(view,params);
            }
        }

        if (pendingRequestFocus) {
            parent.restoreDefaultFocus();
        }

        if (finishInflate) {
            parent.onFinishInflate();
        }
    }
  
   https://www.jianshu.com/p/f1dbcf66b9e1  ----  android UI布局优化之merge标签
  
  
  XmlPullParser.END_DOCUMENT  XmlPullParser.START_TAG
  depth = 
  
  
      viewGroup.addView(view,params);---2022 - 5 - 20 待深入研究
  
    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {----
  
  
  
    public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
                                          @MeasureSpecMode int mode) {
  
  理解MeasureSpec---- https://juejin.cn/post/6844904094205739016
  
  
  MeasureSpec View.
  
  
  系统会将View的LayoutParams根据父容器所施加的规则转换成对应的MeasureSpec,
  
  然后再根据这个measureSpec来测量出View的宽/高。
  
  LayoutParams->MeasureSpec
  
  makeMeasureSpec()
  
  
  SpecMode有三类,每一类都表示特殊的含义,如下所示。
UNSPECIFIED
父容器不对View有任何限制,要多大给多大,这种情况一般用于系统内部,表示一种测量的状态。
EXACTLY
父容器已经检测出View所需要的精确大小,这个时候View的最终大小就是SpecSize所指定的值。它对应于LayoutParams中的match_parent和具体的数值这两种模式。
AT_MOST
父容器指定了一个可用大小即SpecSize,View的大小不能大于这个值,具体是什么值要看不同View的具体实现。它对应于LayoutParams中的wrap_content。

  UNSPECIFIED() UNSPECIFIED
   
  父容器已经检测出View所需要的精确大小,这个时候View的最终大小就是SpecSize所指定的值。
  
  它对应于LayoutParams中的match_parent和具体的数值这两种模式。
  
  
  LayoutParams
  
  EXACTLY
  
  AT_MOST->SpecSize有三类,每一类都表示特殊的含义,如下所示。
  
  
  AT_MOST  它对应于LayoutParams中的wrap_content。
  
  找回密码界面     ->  
  
  makeMeasureSpec        getMode  getSize
  
    
  理解MeasureSpec---- https://juejin.cn/post/6844904094205739016
  
  MeasureSpec->LayoutParams()
  
  
  MeasureSpec不是唯一由LayoutParams决定的,LayoutParams需要和父容器一起才能决定View的MeasureSpec
  
  
  MeasureSpec ->LayoutParams
  
  
  
  对于DecorView,其MeasureSpec由窗口的尺寸和其自身的LayoutParams来共同确定;对于普通View,对于普通View
  
  
  其MeasureSpec由父容器的MeasureSpec和自身的LayoutParams来共同决定 自身的LayoutParams
  
  
  DecorView->MeasureSpec->LayoutParams
  
  
  DecorView->MeasureSpec->LayoutParams
  
  MeasureSpec一旦确定后,onMeasure中就可以确定View的测量宽/高。
  
  
  MeasureSpec(onMeasure View)
  
  于普通View来说,这里是指我们布局中的View, View的measure过程由ViewGroup传递而来,
  
  先看一下ViewGroup的measureChildWithMargins方法:
  
 measureChildWithMargins
  
  子元素的MeasureSpec的创建与父容器的MeasureSpec和子元素本身的LayoutParams有关,
  此外还和View的margin及padding有关
  MeasureSpec ,LayoutParams    margin ,padding
  
  
    理解MeasureSpec---- https://juejin.cn/post/6844904094205739016
  
  一文读懂 View 的 Measure、Layout、Draw 流程-----  https://juejin.cn/post/6939540905581887502
  
  Window 再通过 ViewRootImpl 与 DecorView(视图树的根布局) 进行交互
  
  Window  ViewRootImpl DecorView   Window ViewRootImpl  DecorView  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
 

你可能感兴趣的:(android,webview,linq)