Android布局加载慢,Android布局优化(四)X2C — 提升布局加载速度200%

c9c26cb0dc94?utm_campaign=haruki

系列文章

前言

在Android布局优化(一)从布局加载原理说起中我们说到了布局加载的两大性能瓶颈,通过IO操作将XML加载到内存中并进行解析和通过反射创建View。这里介绍一种避免运行时通过IO操作读取布局文件的“黑科技”—X2C。个人认为这个技术在实际项目中使用可能会需要处理一些兼容性问题,但是从技术人员的思维发散的角度,我认为这其中的一些思想还是很值得学习和借鉴的

背景

一般大家在写页面时都是通过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文件添加依赖

annotationProcessor 'com.zhangyue.we:x2c-apt:1.1.2'

implementation 'com.zhangyue.we:x2c-lib:1.0.6'

2.添加注解

在使用布局的任意java类或方法添加注解即可

@Xml(layouts = "activity_main")

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

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

4.通过X2C加载布局

在原先使用setContentView或inflate的地方替换,如下:

this.setContentView(R.layout.activity_main); --> X2C.setContentView(this, R.layout.activity_main);

LayoutInflater.from(this).inflate(R.layout.activity_main,null); --> X2C.inflate(this,R.layout.activity_main,null);

过程文件

原始的xml

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">

android:id="@+id/head"

layout="@layout/head"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerHorizontal="true" />

android:id="@+id/ccc"

style="@style/bb"

android:layout_below="@id/head" />

生成的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!!! 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标签

应用style

自定义属性

系统属性

属性名称

属性名称

android:textSize

app:layout_constraintRight_toLeftOf

android:textColor

app:layout_constraintBottom_toTopOf

android:text

app:layout_constraintTop_toTopOf

android:background

app:layout_constrainedHeight

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/332562.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

api 获取网络使用情况_您的API是什么情况?

api 获取网络使用情况免责声明:在纯REST中,API是不透明的,URL应该是对先前请求的响应中作为链接发送的内容。 但是,我不是在讲纯REST,而是在讲更实用的API,其中涉及REST的一些概念以及通用的API最佳实践。 …

判断字符串是不是application/x-www-form-urlencoded字符串(URL编码格式的字符串)

import java.util.BitSet;/*** 判断一个字符串是不是URL编码字符串的工具类,即判断字符串是不是application/x-www-form-urlencoded字符串** author liaowenxiong* date 2022/1/14 11:32*/public class URLEncodeUtils {private static BitSet bitSet;static {bitSe…

数据查询和业务流分开_传统数仓和大数据数仓的区别是什么?

概念与容器为什么先说这个,其实很简单:因为绝大多数人都把这两个概念混为一谈。然后就会出现各种各样的问题:oracle不是数据库么,怎么又是数据仓库?Hive不是数据仓库么?怎么又是数据库?数据仓库…

android 多语言不起作用,Android本地化语言环境不起作用,所有区域代码都存在问题...

我需要将除瑞士之类的子语言环境添加到我的应用程序中,而不是普通的德语.我找到的德语资源文件夹的语言环境扩展名为de.所以我的文件夹名为“values-de”.这很好.然后我添加了“values-de_CH”并继续收到错误“无效的资源目录名称”.我也试过“values-de_rCH”和“values-de_ch…

aws 性能_AWS上的应用程序自动扩展–选项和对性能的影响

aws 性能至关重要的是扩展软件应用程序,以避免由于网站的客户群或需要处理大型数据集的应用程序等导致的工作负载增加而导致性能瓶颈的情况。云服务提供商通常是访问其他应用程序的最佳方法随需应变的资源,可根据应用程序的负载变化来放大或缩小。 1.什…

java中月日年这种怎么转换成年月日_最“热乎”的Java社招面试经历分享(共40个面试题)...

面试时间:2020年10月12日1、final finally finalize的区别2、synchronized关键字的作用以及在什么时候使用,concurrent包里面其它的锁。3、有遇到过死锁的问题吗?(死锁的原理和解决方法)4、hashmap的实现原理,hashmap和hashtable的…

(案例)使用Cookie保存用户最后一次访问的时间

文章目录需求分析示例代码需求 1.访问一个Servlet,如果获取不到上一次访问的时间,则提示:您好,欢迎访问。 2.如果可以获取上一次访问的时间,则提示:您好,欢迎回来,您上次访问时间为…

aws lambda使用_使用AWS Lambda,S3和AWS CloudFront进行动态内容缓存

aws lambda使用快速提供内容对于任何网站或应用程序具有更好的客户体验都是必不可少的。 如果您将网站或应用程序托管在AWS Cloud中,那么无论从何处访问应用程序,都可以以较低的延迟快速提供内容。 AWS提供了CloudFront服务,用于将内容缓存在…

android+阴影+xml,Android 阴影视图 ShadowViewHelper

软件介绍ShadowViewHelper 是 Android 的阴影布局。xml:android:id"id/activity_main_shadow_view_b"android:layout_width"wrap_content" android:layout_height"wrap_content"android:layout_gravity"center"android:layout_marginT…

docker-compose观察实时日志_基于 Flink SQL CDC 的实时数据同步方案

整理:陈政羽(Flink 社区志愿者) Flink 1.11 引入了 Flink SQL CDC,CDC 能给我们数据和业务间能带来什么变化?本文由 Apache Flink PMC,阿里巴巴技术专家伍翀 (云邪)分享,内容将从传统的数据同步方案,基于 F…

android dialog 字体,android – 为AlertDialog的MultiSelectItems设置自定义字体(字体)

AlertDialog.Builder使用AlertController.AlertParams构建对话框.我检查了AlertDialog.Builder #create()调用AlertController.AlertParams #application()如果设置了项目,则创建ListView并分配适配器(AlertParams#createListView()).我基于createListView源创建了自定义适配器…

困难是成功路上的垫脚石_Java是开发的垫脚石。 学习吧!

困难是成功路上的垫脚石Java是全世界使用最广泛的编程语言之一 。 尽管也有很多其他编程语言,但是没有什么可以比Java更好的了。 Java是用于开发移动应用程序,游戏,Web应用程序,桌面应用程序和许多其他令人兴奋的事物的出色语言之…

python 3.6.5 shell_Linux 安装 Python3.6.5

1. 安装依赖环境 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel 2. 下载 Python 3.6.5 wget https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tgz 3. 创建安装…

你真的会用Mac中的Finder吗?

参加:https://zhuanlan.zhihu.com/p/144139903

用c语言实现mfc系统,MFC实现学生选课系统

本文实例为大家分享了MFC实现学生选课系统的具体代码,供大家参考,具体内容如下先上效果图:主要功能:输入学号,从数据库中查找学号,若找到相匹配的学号,则显示数据库中姓名、学历、导师&#xff…

spring 构造函数注入_Spring构造函数依赖注入示例

spring 构造函数注入欢迎使用Spring构造函数依赖注入示例指南。 基于构造器的依赖注入是Spring 依赖注入的一种 。 依赖注入的另一种类型是Setter注入和字段注入。 有关Spring依赖注入的更多信息: Spring二传手注射的例子 Spring田间注入 依赖注入–构造函数与现…

python用pip安装numpy mac_Mac下python安装numpy,pandas,matplotlib

numpy是数据分析的库,我的目的是分析股票的数据,Pandas 有两种自己独有的基本数据结构Series (一维)和 DataFrame(二维),它们让数据操作更简单了。它也是 Python 的一个库,所以&…

IntelliJ IDEA for Mac工件包(artifact)中 Web facet resources 的模块名称有误,如何修改?

在工件管理界面中,如果某个工件包中 Web facet resources 的模块名称有误,如下图所示: 你可以在项目根目录下的 .idea/artifacts 目录下找到以工件名称命名的 xml 文件,找到其中含有 facet 属性的 element 标签,更正…

html dom 修改,HTML DOM - 修改

创建新的 HTML 元素如需向 HTML DOM 添加新元素,您首先必须创建该元素(元素节点),然后把它追加到已有的元素上。实例This is a paragraph.This is another paragraph.var paradocument.createElement("p");var nodedocument.createTextNode(&q…