zoukankan      html  css  js  c++  java
  • android 提升布局加载速度200%(X2C)

    背景

     一般大家在写页面时都是通过xml写布局,通过setContentView、或LayoutInflater.from(context).inflate方法将xml布局加载到内存中。

    优点

    • 可维护性好
    • 支持即时预览
    • 代码结构清晰

    缺点

    • 读取xml很耗时
    • 递归解析xml较耗时
    • 反射生成对象的耗时是new的3倍以上

        我们团队在这个问题上也探索过很多解决方案,一度走到了另一个极端,完全废弃xml,所有控件通过java来new,甚至直接在canvas里绘制,这样虽然性能确实提升了,但是代码已经没有了一丁点可读性,可维护性。
        我们后来反思代码到底是给机器看的,还是给人看的??也许X2C已经给了我们一个答案

    有使用问题和其他技术问题,欢迎加群交流讨论

    653583088
    本群提供免费的学习指导以及免费的解答不懂得问题都可以在本群提出来 之后还会有职业生涯规划以及面试指导进群修改群备注:开发年限-地区-经验方便解答问题

    X2C

        为了即保留xml的优点,又解决它带来的性能问题,我们开发了X2C方案。即在编译生成APK期间,将需要翻译的layout翻译生成对应的java文件,这样对于开发人员来说写布局还是写原来的xml,但对于程序来说,运行时加载的是对应的java文件。
        我们采用APT(Annotation Processor Tool)+ JavaPoet技术来完成编译期间【注解】->【解注解】->【翻译xml】->【生成java】整个流程的操作。

    性能对比

    在开发集成完之后我们做了简单的测试,性能对比如下

    加载方式 次数 平均加载时间
    XML 100 30
    X2C 100 11

    集成使用

    1.导入依赖

    annotationProcessor project(':apt')
    implementation project(':lib')
    

    2.添加注解

    @Xml(layouts = {R.layout.activity_main})
    

    3.配置自定义属性(没有可不配)

    在module下建立X2C_CONFIG.xml文件,里面配置定义属性和方法的映射关系,如果接收者是view,则写view.否则填params.

    <x2c-config>
        <attr name="app:mixColor" toFunc="view.setMixColor(int)" />
        <attr name="android:layout_marginTop" toFunc="params.topMargin=int" />
    </x2c-config>
    

    4.通过X2C加载布局

    X2C.setContentView(this, R.layout.activity_main);
    
    X2C.inflate(this,R.layout.activity_main,null);
    

    过程文件

    原始的xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:paddingLeft="10dp">
    
      <include
          android:id="@+id/head"
          layout="@layout/head"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_centerHorizontal="true" />
    
      <ImageView
          android:id="@+id/ccc"
          style="@style/bb"
          android:layout_below="@id/head" />
    </RelativeLayout>
    

    生成的java文件

    
    /**
     * WARN!!! dont edit this file
     * translate from {@link  com.zhangyue.we.x2c.demo.R.layout.activity_main}
     * autho chengwei
     * email chengwei@zhangyue.com
     */
    public class X2C_2131296281_Activity_Main implements IViewCreator {
      @Override
      public View createView(Context ctx, int layoutId) {
            Resources res = ctx.getResources();
    
            RelativeLayout relativeLayout0 = new RelativeLayout(ctx);
            relativeLayout0.setPadding((int)(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,res.getDisplayMetrics())),0,0,0);
    
            View view1 =(View) new X2C_2131296283_Head().createView(ctx,0);
            RelativeLayout.LayoutParams layoutParam1 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
            view1.setLayoutParams(layoutParam1);
            relativeLayout0.addView(view1);
            view1.setId(R.id.head);
            layoutParam1.addRule(RelativeLayout.CENTER_HORIZONTAL,RelativeLayout.TRUE);
    
            ImageView imageView2 = new ImageView(ctx);
            RelativeLayout.LayoutParams layoutParam2 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,(int)(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,res.getDisplayMetrics())));
            imageView2.setLayoutParams(layoutParam2);
            relativeLayout0.addView(imageView2);
            imageView2.setId(R.id.ccc);
            layoutParam2.addRule(RelativeLayout.BELOW,R.id.head);
    
            return relativeLayout0;
      }
    }
    

    生成的映射文件

    /**
     * WARN!!! dont edit this file
     *
     * autho chengwei
     * email chengwei@zhangyue.com
     */
    public class X2C_2131296283 implements IViewCreator {
      @Override
      public View createView(Context context, int layoutId) {
            View view;
            switch(layoutId){
                case 2131296283:
                    view = new X2C_2131296283_Activity_Main().createView(context,2131296283);
                    break;
                case 2131296284:
                    view = new X2C_2131296283_Head().createView(context,2131296284);
                    break;
                default:
                    view = null;
                    break;
            }
            return view;
      }
    }
    
    

    不支持

    • merge标签 ,在编译期间无法确定xml的parent,所以无法支持
    • 系统style,在编译期间只能查到应用的style列表,无法查询系统style,所以只支持应用内style

    支持

    • 各种系统控件、自定义控件
    • include标签
    • ViewStub标签
    • fragment标签
    • 应用style
    • 自定义属性
    • 系统属性
    属性名称 属性名称
    android:textSize app:layout_constraintRight_toLeftOf
    android:textColor app:layout_constraintBottom_toTopOf
    android:text app:layout_constraintTop_toTopOf
    android:background app:layout_constrainedHeight
    ...  


    有使用问题和其他技术问题,欢迎加群交流讨论

    653583088
    本群提供免费的学习指导以及免费的解答不懂得问题都可以在本群提出来 之后还会有职业生涯规划以及面试指导进群修改群备注:开发年限-地区-经验方便解答问题

  • 相关阅读:
    QML控件设置style样式
    QML:ListElement: cannot use script for property value
    内存更换乌龙事件
    服务器的寿命到底有多长
    这些年渠道管理系统上发生的那些事
    IT囧事之误删测试环境的生产库
    旁观一个软件产品的终结
    一根网线引发的血案
    论代码规范命名的重要性
    服务器故障之内存损坏
  • 原文地址:https://www.cnblogs.com/876013676ch/p/10187287.html
Copyright © 2011-2022 走看看