# X2C **Repository Path**: ouyangpengdev/X2C ## Basic Information - **Project Name**: X2C - **Description**: Increase layout loading speed 200% - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2021-03-23 - **Last Updated**: 2024-12-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 背景 [English](README.md)  一般大家在写页面时都是通过xml写布局,通过setContentView、或LayoutInflater.from(context).inflate方法将xml布局加载到内存中。 #### 优点 * 可维护性好 * 支持即时预览 * 代码结构清晰 #### 缺点 * 读取xml很耗时 * 递归解析xml较耗时 * 反射生成对象的耗时是new的3倍以上     我们团队在这个问题上也探索过很多解决方案,一度走到了另一个极端,完全废弃xml,所有控件通过java来new,甚至直接在canvas里绘制,这样虽然性能确实提升了,但是代码已经没有了一丁点可读性,可维护性。     我们后来反思代码到底是给机器看的,还是给人看的??也许X2C已经给了我们一个答案 # X2C     为了即保留xml的优点,又解决它带来的性能问题,我们开发了X2C方案。即在编译生成APK期间,将需要翻译的layout翻译生成对应的java文件,这样对于开发人员来说写布局还是写原来的xml,但对于程序来说,运行时加载的是对应的java文件。     我们采用APT(Annotation Processor Tool)+ JavaPoet技术来完成编译期间【注解】->【解注解】->【翻译xml】->【生成java】整个流程的操作。 # 性能对比 在开发集成完之后我们做了简单的测试,性能对比如下 | 加载方式|次数|平均加载时间| | ------ | ------ | ------ | |XML|100|30| |X2C|100|11| # 集成使用 #### 1.导入依赖 在module的build.gradle文件添加依赖 ```java annotationProcessor 'com.zhangyue.we:x2c-apt:1.1.2' implementation 'com.zhangyue.we:x2c-lib:1.0.6' ``` #### 2.添加注解 在使用布局的任意java类或方法添加注解即可 ```java @Xml(layouts = "activity_main") ``` #### 3.配置自定义属性(没有可不配) 在module下建立X2C_CONFIG.xml文件,里面配置定义属性和方法的映射关系,如果接收者是view,则写view.否则填params. ```mxl ``` #### 4.通过X2C加载布局 在原先使用setContentView或inflate的地方替换,如下: ```java this.setContentView(R.layout.activity_main); --> X2C.setContentView(this, R.layout.activity_main); ``` ```java LayoutInflater.from(this).inflate(R.layout.activity_main,null); --> X2C.inflate(this,R.layout.activity_main,null); ``` # 过程文件 #### 原始的xml ```xml ``` #### 生成的java文件 ```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; } } ``` #### 生成的映射文件 ```java /** * WARN!!! don't edit this file * * author chengwei * email chengwei@zhangyue.com */ public class X2C127_activity implements IViewCreator { @Override public View createView(Context context) { View view = null ; int sdk = Build.VERSION.SDK_INT; int orientation = context.getResources().getConfiguration().orientation; boolean isLandscape = orientation == Configuration.ORIENTATION_LANDSCAPE; if (isLandscape) { view = new com.zhangyue.we.x2c.layouts.land.X2C127_Activity().createView(context); } else if (sdk >= 27) { view = new com.zhangyue.we.x2c.layouts.v27.X2C127_Activity().createView(context); } else if (sdk >= 21) { view = new com.zhangyue.we.x2c.layouts.v21.X2C127_Activity().createView(context); } else { view = new com.zhangyue.we.x2c.layouts.X2C127_Activity().createView(context); } return view; } } ``` # 不支持 * merge标签 ,在编译期间无法确定xml的parent,所以无法支持 * 系统style,在编译期间只能查到应用的style列表,无法查询系统style,所以只支持应用内style # 支持 * 兼容ButterKnifer * 兼容DataBinding * 各种系统控件、自定义控件 * include标签 * viewStub标签 * fragment标签(感谢[Dreamskya](https://github.com/Dreamskya))提出宝贵意见 * 应用style * 自定义属性(感谢[Anzhi-Meiying](https://github.com/Anzhi-Meiying)提出的宝贵意见) * 系统属性 | 属性名称|属性名称| | ------ |------- | |android:textSize| app:layout_constraintRight_toLeftOf| |android:textColor| app:layout_constraintBottom_toTopOf| |android:text| app:layout_constraintTop_toTopOf| |android:background| app:layout_constrainedHeight| |[查看全部](supportAll.md)| ## 有使用问题和其他技术问题,欢迎加群交流讨论 > QQ群:`870956525`,添加请注明来自`X2C` > > 掌阅X2C交流群 > > 欢迎各位使用,该项目会持续维护。 > > > 另:欢迎加入[掌阅](http://www.zhangyue.com/jobs)大家庭,一起研究Android新技术。简历请发送`huangjian@zhangyue.com`,注明应聘方向。 > # LICENSE ``` MIT LICENSE Copyright (c) 2018 zhangyue Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ```