一个减少冗余Drawable资源的解决方案

简介: 一个减少冗余Drawable资源的解决方案

1. 前言


最近鸿洋大神和路遥大佬分别在他们的公众号上发布了关于解决Shape/Selector冗余的方案。这篇文章在上周末就已经写好了。虽然类似的解决方案特别多,实现思路也都差不多。但我仍然要安利一下我的这个解决方案。原因有以下几点。

  1. 很纯粹,就是用代码的方式实现了xml实现的Drawable,不用重写自定义View或者Hook系统的基础组件。
  2. 最大程度的复刻xml所拥有的能力,甚至连单位dp还是px的api都提供好了。
  3. 使用Builder模式将方法和参数都约束起来,使用起来很方便,不用去众多的api中寻找方法。结合Kotlin的语法,一个字“香”。
  4. 内部实现了缓存策略,以及根据Hash判重策略,这也是目前市面上的其他解决方案所没有的。

当然美中不足的是,目前所有的xml替换都是需要手工去完成,如果在编译期能够通过gradle插件自动转换,那就完美了。如果您有相关的经验,可以尝试一起把这个库做得更好。


2. Android为什么用xml生成Drawable


xml是Android系统中生成Drawable的首选方案,所以很多同学都习惯了使用xml生成GradientDrawable和SelectorDrawable,它们确实很方便。但是随之而来的问题,我相信很多同学都是深有体会的,哪怕是GradientDrawable中一个圆角大小的改动,或者一个颜色值的改动,都需要在原来的xml文件基础上拷贝一份新的xml文件,这样导致项目中的drawable文件越来越多。甚至一些编码规范没做好的团队,明明完全一样效果的drawable在项目中也有可能出现多份。


针对这种情况,有没有必要处理呢?大部分的xml文件也就1 2kb,占用空间很小,对包体积大小影响也没那么大。虽然说Android系统Drawable缓存是以文件名为维度的,但是它的回收策略做的挺棒的,冗余的xml对内存占用有影响,但没那么大。


那就任由文件数量膨胀吗?我觉得答案是见仁见智的,不处理也可以,无非就是写起来臃肿点呗,至少不用花时间去想一套解决方案。当然我们也可以精益求精,使用代码生成Drawable方案,实现与xml完全一样的效果,同时又能避免冗余的xml文件出现。


意外的收获👉 在项目使用svg作为图片时,发现在Android5.0 和Android6.0手机上,xml定义的selector图片显示不正常。究其原因是因为Android7.0以下不支持svg格式的fillType,导致selector渲染出来的图片有问题。想了很多方法都无法解决,最终通过代码生成selector的方案解决了。


在开始写通过代码生成Drawable之前,首先思考一个问题?为什么Android系统会首选xml生成Drawable方案呢?

通过分析xml渲染Drawable原理,我觉得系统兼容可能是使用xml的一个重要原因。以GradientDrawable的setPadding方法为例,该方法在Android Q版本引入。如果我们在xml文件引入padding,在Android Q以下版本也不会出问题。如果是代码中使用就需要做版本判断


<padding android:top="10dp" android:bottom="10dp" android:left="10dp" android:right="10dp"></padding>



闲话少叙,先看看最终的效果,下图左边是通过xml生成GradientDrawable,右边是通过代码生成GradientDrawable效果。

640.png

640.png


3. xml实现和代码实现


看下具体代码实现


  1. GradientDrawable xml实现

640.png

GradientDrawable代码实现

640.png

StateListDrawable xml实现


640.png

StateListDrawable 代码实现

640.png

addState(StatePressed)方法表示android:state_pressed="true"


minusState(StatePressed)方法表示android:state_pressed="false"


当然也可以添加多个状态


640.png


4. 特性以及源码


该库有以下特性:


  1. xml能实现的,它全部能实现
  2. 使用Builder模式,更容易构建Drawable
  3. 支持所有的android:state_xxx
  4. GradientDrawable,只要所有构建的参数内容一样(顺序可以打乱),内存中只会保留一份
相关文章
|
6月前
|
Linux 编译器 C++
C/C++性能优化:从根本上消除拷贝操作的浪费
C/C++性能优化:从根本上消除拷贝操作的浪费
793 0
|
存储 缓存 数据库
优化性能与减少资源浪费:深入了解缓存策略
缓存策略是现代Web开发中关键的优化技术之一,它可以显著提高网站性能,降低服务器负载,并减少用户等待时间。在本博客中,我们将深入研究缓存策略的概念、不同类型的缓存和如何在项目中实施它们。
201 0
|
24天前
|
存储 监控 Linux
充分利用服务器的磁盘资源,提高系统的稳定性和可维护性
充分利用服务器的磁盘资源,提高系统的稳定性和可维护性
31 0
|
3月前
|
监控 Java 开发工具
### 绝招揭秘!Android平台GB28181设备接入端如何实现资源占用和性能消耗的极限瘦身?
【8月更文挑战第14天】本文介绍在Android平台优化GB28181标准下设备接入的性能方法,涵盖环境搭建、SDK集成与初始化。重点讲解内存管理技巧如软引用、按需加载资源,以及通过硬件加速解码视频数据和图像缩放来减轻CPU与GPU负担。同时采用线程池异步处理视频流,确保UI流畅性。这些策略有助于提高应用效率和用户体验。
44 0
|
4月前
|
供应链
软件架构一致性问题之通过减少修改次数降低软件供应链管理的成本如何解决
软件架构一致性问题之通过减少修改次数降低软件供应链管理的成本如何解决
42 0
|
4月前
|
消息中间件 存储 Java
三类代码协同模式问题之压缩异常输出以提高性能和节省存储空间的问题如何解决
三类代码协同模式问题之压缩异常输出以提高性能和节省存储空间的问题如何解决
|
编解码 监控 前端开发
Android平台GB28181设备接入端如何降低资源占用和性能消耗
Android平台GB28181设备接入端如何降低资源占用和性能消耗?
|
缓存 Java
性能优化之@Contended减少伪共享
说到伪共享,就要说CPU缓存,我们程序执行时候信息会被保存到CPU缓存中 而这些缓存中的数据可能被多线程访问,假如一个线程还没处理完,另外一个线程 就对数据进行了修改,就会导致上一个线程发生幻读的情况,比如刚才看到a=1,然后准备a = a+1。 但是还没做,另外一个线程就先将a变成2了。导致了上一个线程计算后本来应该是a = 1 + 1,变成了a = 2 + 1 计算结果就不对了。
443 0
|
存储 监控 架构师
避免云端浪费的5种方法
很多企业采用云计算的一个重要原因是为了避免建设和运营服务器机房或数据中心的费用以节省成本。但是,如果没有正确采用云计算技术,仍然会遭受资金损失。因此需要避免一些代价高昂的错误方法。
217 0
|
Java 分布式数据库 Hbase
干货 | 如何优雅的通过Key与Value分离降低写放大难题?
LSMs(Log Structured Merge Trees)结构在现今数据存储系统中非常流行,很多著名系统,包括 Google BigTable,HBase,RocksDB,Apache Cassandra 等等都采用了这一结构。
3210 0