Android Virtualview:淘宝、天猫又开源了一个动态化、高性能的UI框架
转载 Carson_Ho
Android Virtualview:淘宝、天猫又开源了一个动态化、高性能的UI框架
- 前言
- 目录
- 1. 为什么要向 Tangram模型 加入 VirtualView
- 2. VirtualView介绍
- 3. 实现原理
- 核心思路
- 实现方案
- 总结
- 4. 工作流程
- 流程概述
- 流程详细分析
- 流程1:创建UI组件
- 1. 使用框架内置(封装好)的UI组件
- 2. 自定义UI组件
- 3. 总结
- 流程2:创建界面模板 & 下发
- 1. 创建XML界面模板
- 2. 编译成二进制数据
- 具体描述
- 二进制文件描述
- 编译流程
- 3. 模板数据下发到客户端
- 流程3:客户端加载界面
- 1. 解析模板数据
- 2. 加载组件视图
- 3. 绑定业务数据
- 4. 总结
- 5. 整体架构设计
- 模块1:加载模块
- 模块2:构造模块
- a. 基础组件模型
- 模块3:辅助模块
- 模块4:管理模块
- 模块5:更新模块
- 配套使用的工具 & 服务
- 总结
- 6. 使用教程
- 6.1 创建UI组件
- 6.2 创建界面模板
- 6.2.1 创建XML界面模板
- 6.2.2 编译成二进制数据
- 6.2.3 模板下发到客户端
- 6.3 客户端解析 & 加载界面模板
- 7.VirtualView 的意义
- 7.1 对于 Tangram 模型
- 7.2 对于整个原生开发技术(Android、iOS)
- 7.3 呼吁
- 8. 总结
前言
淘宝、天猫一直致力于解决 页面动态化 的问题
在2017年的4月发布了v1.0解决方案:Tangram模型 及其对应的 Android库 vlayout,该解决方案在手机淘宝、天猫 Android版 内广泛使用
若还不了解Tangram模型 和 vlayout,具体请看文章
Android Tangram模型:连淘宝、天猫都在用的UI框架模型你一定要懂
Android开源库V - Layout:淘宝、天猫都在用的UI框架,赶紧用起来吧!在同年的12月,阿里团队对此作了重大更新:发布了Tangram2.0版本,主要是补充了Android库VirtualView,也广泛应用于淘宝、天猫客户端
今天,我将带大家全面了解Tangram 2.0版本的新成员:Virtualview,Virtualview的Github地址
目录
1. 为什么要向 Tangram模型 加入 VirtualView
即 为什么要更新 Tangram2.0版本
- 结论
- 提升组件动态性,实现动态更新
- 提升了组件的渲染性能
- 具体描述
而上述解决方案的承载方案,则是 VirtualView
VirtualView的Github地址
2. VirtualView介绍
- 简介
- 特点
3. 实现原理
核心思路
根据Tangram v1.0中 出现的问题:UI组件无法动态更新 & 加载性能低,VirtualView的具体解决方案如下
实现方案
- 根据其原理,VirtualView的实现方案是:虚拟化开发
- 虚拟化开发的本质:
之所以称为虚拟化,是因为Canvas绘制的视图不存在一一对应的实体View
总结
从上可知,VirtualView的创新在于:
- 通过 XML 模板实现组件的动态性
- 通过 虚拟化技术(本质 = Canvas)开发组件,提升了组件的渲染性能
4. 工作流程
- 在了解了VirtualView的本质原理 & 整体架构后
- 下面,我将开始讲解VirtualView的工作流程
流程概述
- 根据上述方案,VirtualView的工作流程分为3大部分:创建UI组件、创建界面模板 & 客户端加载界面
- 具体如下
流程详细分析
下面我将对每个流程的原理 & 过程详细分析
流程1:创建UI组件
- 具体描述
根据业务需求,创建所需要的UI组件
有2种创建方式:使用框架内置(封装好)的UI组件 / 自定义
1. 使用框架内置(封装好)的UI组件
- 即 可
直接使用封装好的UI组件而不需自身创建
- 具体如下(含组件基础属性)
注:a.自定义组件应继承基础组件
b. 系统封装UI组件的原理 同 “自定义UI组件,下面将具体讲解
2. 自定义UI组件
若框架内置的UI组件无法满足需求,则开发者可自定义UI组件
自定义流程
VirtualView抽象 & 封装了 Canvas绘制视图的流程,使得开发者只需按指定的接口协议实现1个组件的绘制逻辑
:测量、布局 & 绘制
,即能实现在宿主容器通过 Canvas 直接绘制 UI内容,从而创建虚拟化组件。
即 上述则是虚拟化创建组件的过程具体过程
1.
实现基础组件需遵循一个接口的规范:定义了渲染过程中所需的3个流程:测量尺寸阶段、布局阶段 & 绘制阶段
- a.
定义这3个阶段是为了符合Android系统的使用,即View绘制的三大流程:measure过程、layout过程、draw过程
。若不了解,请看文章
(2)自定义View Measure过程 - 最易懂的自定义View原理系列
(3)自定义View Layout过程 - 最易懂的自定义View原理系列
(4)自定义View Draw过程- 最易懂的自定义View原理系列 - b. 在 iOS 平台下也需按照本方案的规范去处理
- a.
2.这3个过程具体如下:(与Android View绘制的三大流程相似)
不论是虚拟 / 原生组件,都采用上述模型 & 流程定义
a. 对于虚拟组件:在这些接口里实现相关逻辑 / 通过封装原生组件实现
b. 对于原生组件:在这些接口的实现里 调用原生组件的对应逻辑
结论:可混合使用虚拟控件 & 实体控件
至此,对于宿主的布局容器来说,包装在内部的组件不分虚拟化 / 原生,暴露在外的接口相同,只要将宿主容器像普通的 View 一样添加到的视图界面上,就可在后续的渲染过程中显示出来。
- 特别注意
此处即可解释 为何渲染性能高:因虚拟组件使用得越多,View个数就越少,即层级越扁平
如下所示的组件:
- 普通的原生开发:2层(宿主容器层 + 图片组件层)
- 虚拟化开发:采用虚拟化开发后,最终呈现的 View层级只有一个宿主容器(实际上,图片组件被绘制在Canvas里了)
3. 总结
创建UI组件有2种方式:
- 直接使用框架内置的UI组件
- 自定义组件:通过封装好的Canvas流程,按照指定接口协议实现绘制逻辑 / 封装原生组件
流程2:创建界面模板 & 下发
- 该步骤包括多个步骤:创建XML界面模板、编译成二进制数据、下发等
- 具体如下
1. 创建XML界面模板
具体描述
根据业务需求,使用XML编写模板
注:需使用专门的工具virtualview_tools编写,其使用说明见文章virtualview_tools使用指南此方式类似:Android 平台上通过 XML 搭建界面的方式
区别在于:
- 脱离了平台限制,即一套模板可同时在Android、iOS上使用
- 运行时动态加载 XML 模板数据,动态更新界面结构
// 引用的组件通过流程1中获取 // 动态数据通过表达式从 JSON 数据里获取<?xml version="1.0" encoding="utf-8"?> <VHLayoutflag="flag_exposure|flag_clickable"orientation="H"layoutWidth="match_parent"layoutHeight="wrap_content"><NImageid="1"src="${logoUrl}"layoutMarginLeft="8"layoutMarginRight="8"layoutMarginTop="8"layoutMarginBottom="8"layoutWidth="32"layoutHeight="32"/><NTextid="2"text="${title}"layoutGravity="v_center"gravity="${style.text-align}"textSize="${style.font-size}"textColor="${style.color}"layoutWidth="match_parent"layoutHeight="wrap_content"/> </VHLayout>// JSON数据 {"style": {"text-align": "h_center","font-size": "20","color": "#FF5000"},"title": "超高性 99.9% 的用户觉得很快","logoUrl": "https://gw.alicdn.com/tfs/TB1yGIdkb_I8KJjy1XaXXbsxpXa-72-72.png" }
2. 编译成二进制数据
具体描述
使用专门的工具virtualview_tools将编写好的XML界面模板编译成二进制数据,编译后的文件的后缀名是.out
使用说明见文章virtualview_tools使用指南
注:为什么通过 XML 编写的业务组件 不直接在客户端里运行使用,而是先进行一次二进制序列化操作?
二进制文件描述
借鉴了 Android 系统编译模板文件的思路,格式 & 描述具体如下
编译流程
- 一个业务组件对应着一份 XML 模板 = 单独编译成二进制数据
编译数据 含除内置字符串资源外 它依赖的所有字符串、表达式资源 - 编译规则
编译时,模板里涉及的资源包括颜色值、各种枚举、基础组件的类型等都会被序列化映射成整数;不能序列化成整数的资源如字符串,就分配一个索引 Id 指向它 & 将它们单独存储到一块区域里- 原因:当模板在线发布、字符串有变动的情况下,能够不影响原来的字符串资源索引;否则若按照带有顺序约定的协议来分配资源索引,很容易在模板变更时 同一索引值在变更前后指向的资源内容是不一样,影响稳定性和动态性
- 序列化的规则如下:
- 编译流程
3. 模板数据下发到客户端
即 客户端获取编译后的二进制数据
获取有2种路径:
- 直接将编译后的模板打包到客户端里,开发者通过代码加载
- 框架先发布到模板管理后台,客户端在线更新到模板数据(即实现了动态更新)
流程3:客户端加载界面
- 客户端获取到编译后的界面模板后,进行加载 & 解析,最终渲染出视图界面
- 步骤流程如下图
1. 解析模板数据
具体描述
客户端获得编译后的模板数据(二进制数据)后,立即 进行解析- 如校验版本号,合法性,读取头信息等
- 客户端渲染组件 从解析 编译后的模板数据开始
流程解析
解析过程 = 二进制编译的逆过程
但解析流程只负责提取原始数据 & 组织格式,并无构建出组件对象
2. 加载组件视图
- 具体描述
当用户传入一个模板名称,框架内部就会根据名称去之前解析XML界面模板的数据里找到 与此名称匹配的模板数据,然后加载 & 创建出真正的组件 - 流程解析
3. 绑定业务数据
- 具体描述
开发者在组件属性里可通过 表达式指定使用哪个数据字段,即将业务数据绑定到组件上
因业务数据是动态的,故从模板创建的组件不含业务数据
- 流程解析
在创建组件的过程中,当解析属性碰到表达式时,会将该属性的key、表达式值、所属的基础组件等关系存储起来,等真实数据到达后再通过 表达式里的定义 访问数据 & 将真实值设置给组件的属性,即将真实的数据绑定到基础组件的属性上- 通过表达式解析、访问得到的属性值,会缓存起来,当原始数据引用不变时,每次访问都会获取到缓存值
- 此处接收的数据是 JSON 格式
4. 总结
5. 整体架构设计
- 根据上述方案 & 工作流程,VirtualView的整体框架分为2部分:核心功能模块(5个模块) + 配套工具 & 服务。具体如下:
下面,我将对每部分进行详细分析
模块1:加载模块
- 示意图
- 说明
模块2:构造模块
- 示意图
- 说明
此处详细分析 基础组件模型 & 虚拟组件
a. 基础组件模型
含基础组件 & 基础属性,具体如下
注:自定义的基础组件应继承基础定义 & 扩展
模块3:辅助模块
- 示意图
- 说明
- 特别注意:引入用户数据绑定的表达式的原因
开发业务组件时,基础属性 / 样式不能在模板里直接写死,而是需从数据里动态获取
/*** 访问数据属性的表达式* 语法说明* a. 以 “${” 开头、以 “}” 结束* b. 对于Map,通过“.”操作符访问* c. 对于 Array / List,通过 “[]” 操作符访问* 示例如下*/${benefitImgUrl};${data[0].benefitImgUrl};/*** 条件表达式* 作用:根据数据中某个字段 来设置值的属性* 语法说明* a. 以 “@{” 开头、以 “}” 结束,* b. 中间部分 = 表达式的具体内容: 条件表达式 ? 结果表达式[1] : 结果表达式[2]* 注:1. 当条件表达式成立的时,使用结果表达式[1],否则使用结果表达式[2]* 2. 条件表达式支持布尔类型、字符串类型、JSONObject、JSONArray* c. 对于 Array / List,通过 “[]” 操作符访问* 示例如下*/@{${logoUrl} ? visible : invisible };
模块4:管理模块
- 示意图
- 说明
模块5:更新模块
- 示意图
- 说明
配套使用的工具 & 服务
- 示意图
- 说明
总结
6. 使用教程
- 根据上述工作流程,其使用流程同样分为3步:创建UI组件、创建界面模板 & 客户端加载界面
- 下面,我将根据上述3个步骤进行详细解析
6.1 创建UI组件
从一文可知,创建UI组件有2种方式:
- 直接使用框架内置的UI组件
- 自定义组件:通过封装好的Canvas流程,按照指定接口协议实现绘制逻辑 / 封装原生组件
此处为方便讲解,直接使用框架内置的UI组件
6.2 创建界面模板
此步骤包括:创建XML界面模板、编译成二进制数据、模板下发
6.2.1 创建XML界面模板
根据业务需求,使用XML编写模板
注:需使用专门的工具virtualview_tools编写,其
使用说明见文章virtualview_tools使用指南
示例布局
/*** 使用说明:* 1. 控件引用:通过XML引用控件为方便讲解,XML内引用的VHLayout、NImage、NText 都是框架内置的控件:2个横向线性布局;每个布局 = 1个图 + 1个文本* 2. 属性设置:可写死 / 通过表达式绑定一个数据字段(JSON)引用* 布局说明:* 1. 引用的控件VHLayout、NImage、NText等都是框架内置的控件* 2. 整个布局 = 2个横向线性布局,每个布局 = 1个图 + 1个文本*/<?xml version="1.0" encoding="utf-8"?> <VHLayoutflag="flag_exposure|flag_clickable"orientation="V"layoutWidth="match_parent"layoutHeight="wrap_content"><VHLayoutflag="flag_exposure|flag_clickable"orientation="H"layoutWidth="match_parent"layoutHeight="wrap_content"><NImageid="1"src="${logoUrl}"layoutMarginLeft="8"layoutMarginRight="8"layoutMarginTop="8"layoutMarginBottom="8"layoutWidth="32"layoutHeight="32"/><NTextid="2"text="${title}"layoutGravity="v_center"gravity="${style.text-align}"textSize="${style.font-size}"textColor="${style.color}"layoutWidth="match_parent"layoutHeight="wrap_content"/></VHLayout><VHLayoutflag="flag_exposure|flag_clickable"orientation="H"layoutWidth="match_parent"layoutHeight="wrap_content"><VImageid="1"src="${logoUrl}"layoutMarginLeft="8"layoutMarginRight="8"layoutMarginTop="8"layoutMarginBottom="8"layoutWidth="32"layoutHeight="32"/><VTextid="2"text="${title}"layoutGravity="v_center"gravity="${style.text-align}"textSize="${style.font-size}"textColor="${style.color}"layoutWidth="match_parent"layoutHeight="wrap_content"/></VHLayout> </VHLayout>
属性数据来源:JSON
{"style": {"text-align": "h_center","font-size": "20","color": "#FF5000"},"title": "超高性 99.9% 的用户觉得很快","logoUrl": "https://gw.alicdn.com/tfs/TB1yGIdkb_I8KJjy1XaXXbsxpXa-72-72.png" }
6.2.2 编译成二进制数据
使用专门的工具virtualview_tools将编写好的XML界面模板编译成二进制数据,编译后的文件的后缀名是.out
使用说明见文章virtualview_tools使用指南
6.2.3 模板下发到客户端
有2种路径:
- 直接将编译后的模板打包到客户端里,开发者通过代码加载
- 框架先发布到模板管理后台,客户端在线更新到模板数据(即实现了动态更新)
此处选择方式1
6.3 客户端解析 & 加载界面模板
具体使用如下
// 1. 初始化图片加载器 VafContext.loadImageLoader(mContext.getApplicationContext());// 2. 初始化 ViewManager 对象 ViewManager viewManager = vafContext.getViewManager(); viewManager.init(mContext.getApplicationContext());// 3. 加载编译后的模板数据(二进制文件)// 方式1:直接加载二进制字节数组(推荐使用)viewManager.loadBinBufferSync(TMALLCOMPONENT1.BIN);viewManager.loadBinBufferSync(TMALLCOMPONENT2.BIN);// 方式2:通过二进制文件路径加载viewManager.loadBinFileSync(TMALLCOMPONENT1_PATH);viewManager.loadBinFileSync(TMALLCOMPONENT2_PATH);// 4. 注册事件处理器,如常用的点击、曝光处理 vafContext.getEventManager().register(EventManager.TYPE_Click, new IEventProcessor() {@Overridepublic boolean process(EventData data) {//handle herereturn true;} }); vafContext.getEventManager().register(EventManager.TYPE_Exposure, new IEventProcessor() {@Overridepublic boolean process(EventData data) {//handle herereturn true;} });// 5. 通过组件名参数 name 生成组件实例 View container = vafContext.getContainerService().getContainer(name, true); mLinearLayout.addView(container);// 6. 为组件绑定真实的数据 // 假若您在组件模板里写了数据绑定的表达式 IContainer iContainer = (IContainer)container; JSONObject json = getJSONDataFromAsset(data); if (json != null) {iContainer.getVirtualView().setVData(json); }
测试结果
下图展示的“超高性 99.9% 的用户觉得很快”即为VirtualView的展示效果
至此,关于VirtualView的使用讲解完毕
更加详细使用,请参考文章VirtualView的使用文档
7.VirtualView 的意义
对于个人的看法,VirtualView的补充其重大意义在于2个方面:对于 阿里Tangram 模型 & 整个原生开发技术(Android、iOS)
7.1 对于 Tangram 模型
VirtualView的解决的问题 在于:
- 实现组件的动态性:可在端上绑定动态下发的 XML 界面模板 & 数据
- 提升了组件的渲染性能:通过 虚拟化技术(本质 = Canvas)开发组件
7.2 对于整个原生开发技术(Android、iOS)
VirtualView的创新在于:解决了 原生开发中一直被诟病 而 常被叫喧会被 前端、RN技术取代的问题:
开发周期长 & 成本大
VirtualView 采用XML描述视图,XML界面模板具备跨平台使用的特性无法热更新
VirtualView可在端上绑定动态下发的 XML 界面模板 & 数据,从而实现热更新
相比于前几年产品开发的一味求快,如今互联网行业发展暂缓、用户需求基本满足的情况下,更加 讲求的是用户体验
所以,实际上对比于 前端、RN技术在客户端的实现,VirtualView的优势或许会更明显:在解决了原生开发效率慢、周期长的前提下,保证了原生开发的优势:性能好
7.3 呼吁
- 虽然VirtualView 推动了原生开发的发展,但目前来说,VirtualView 还是存在不少问题
- 希望大家能一起在Github - alibaba - VirtualView 上进行完善,共同为开源事业做贡献吧!
8. 总结
- 看完本文,你应该非常了解阿里出品的VirtualView 的使用 & 原理
- 关于Tangram的使用,建议看文章:
Android Tangram模型:连淘宝、天猫都在用的UI框架模型你一定要懂
Android开源库V - Layout:淘宝、天猫都在用的UI框架,赶紧用起来吧!
Android Virtualview:淘宝、天猫又开源了一个动态化、高性能的UI框架相关推荐
- Android Virtualview:淘宝、天猫 又一个动态化、高性能的UI框架力作
Android Virtualview:淘宝.天猫 又一个动态化.高性能的UI框架力作 前言 淘宝.天猫一直致力于解决 页面动态化的问题 在2017年的4月发布了v1.0解决方案:Tangram模型 ...
- Android Virtualview:淘宝、天猫又开源了一个动态化、高性能的UI框架力作
前言 淘宝.天猫一直致力于解决 页面动态化的问题 在2017年的4月发布了v1.0解决方案:Tangram模型 及其对应的 Android库 vlayout,该解决方案在手机淘宝.天猫 Android ...
- 淘宝天猫背后,有一个你不知道的神秘组织
对大部分人来说,生活中最熟悉的是那些贴近日常的服务:不论是淘宝.天猫,还是优酷.闲鱼,它们和我们最密切,因为你可能天天都会用到.但当提到阿里巴巴电商业务中台时,我相信身边大部分人会感觉很陌生,的确,这 ...
- android动态化ui框架,动态化高性能的 UI 框架 Virtualview-Android
软件介绍 Virtualview-Android 是一个虚拟化组件,是 Tangram 模型在 2.0 版本补充的 UI 开源库.它开创了一种虚拟化开发基础控件的技术,使用方只要按照指定协议实现一个基 ...
- 淘宝天猫重组换血,原核心高管离职;Google Bard 大更新,数学和逻辑能力有所提升;K8s 1.27 发布|极客头条
「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧. 整理 | 梦依丹 出品 | CSDN(ID:CSDNnews ...
- 淘宝/天猫获得淘宝app商品详情原数据
淘宝/天猫获得淘宝app商品详情原数据 API 返回值说明 立即测试 item_get_app-获得淘宝app商品详情原数据 获取Key和secret 请求参数 请求参数:num_iid=5 ...
- 淘宝/天猫获得淘宝app商品详情原数据API,电商数据分析
万邦淘宝/天猫获得淘宝app商品详情原数据 API 返回值说明 item_get_app-获得淘宝app商品详情原数据 onebound.taobao.item_get_app 公共参数 请求地址: ...
- 淘宝天猫优惠券客户端(duilib版)
淘宝天猫优惠券客户端(duilib版) 淘宝购物在于淘的过程,科技进步,生活节奏加快,如何在有限的时间里找到自己想买的优质商品?来这里:51优惠券!海量优质商品优惠券,购物前先领优惠券,价格肯定比直接 ...
- API测试接口,淘宝天猫、1688、京东、拼多多商品页面APP端原数据,API返回值说明
以下是行业内了解到的一些情况,本帖只展示部分代码,需要更多API调试请移步注册API账号 console.open.onebound.cn/console/?i=- 淘宝/天猫获得淘宝app商品详情原 ...
最新文章
- Jquery实现form表单回填数据
- java基础学习(1)-jre与jdk
- 全国各省“光棍”排名,数据揭秘哪里脱单最难?
- 时间管理-暗世界-时间碎片
- 动态切换数据源(spring+hibernate)
- html如何实现页面懒加载,浏览器HTML自带懒加载技术
- 51CTO博客——架起我与读者沟通、见面的桥梁[博友话题]
- 过拟合产生的原因有哪些
- 远程通讯测试软件,USR-TCP232-304和虚拟串口软件通讯测试
- 本来都对象棋失去兴趣了, 是特殊的原因让我又开始从侧面搞象棋方面的擦边的游戏...
- Linux服务器上修改深度学习代码
- PC比电脑好玩的秘密是什么?答案就是因为有这些神奇的网站!
- java -jar 执行jar包出现 java.lang.NoClassDefFoundError
- leetcode 714 买卖股票的最佳时机含手续费-动态规划(中等)
- 企业上线MES软件的费用真的很贵?
- HiveSql工作中常见易错点总结
- rtcp 的jitter buffer
- 一个大学毕业生的反思
- 艾兰岛编辑器-全局存储
- 纪念相对论发表110周年