java - 使用 HashMap 中的复合键优化许多 LinearGradient 着色器的 onDraw

标签 java android performance hashmap

我正在编写我的第一个 Android 应用程序(也是过去 15 年来我的第一个 Java 应用程序)。它采用编码字符串并将代码转换为绘图操作。一些代码代表渐变定义,这就是我的问题所关心的。

如果我理解正确,尝试在 onDraw 函数(我的扩展 View 类中的覆盖)期间创建任何类型的新对象将导致 lint 输出警告,提示在 onDraw 期间缓存对象并且从不分配新对象。所以我决定尝试对代码字符串定义的所有渐变进行缓存。这样,如果您以相同的尺寸重新绘制相同的代码,则不必重新分配该代码定义的渐变。

在尝试定义 HashMap 的键结构时遇到了问题,我认为这是缓存的最佳结构。如果我可以简单地使用将渐变定义为键的代码 fragment (字符串),那就太好了,但我认为这不会很好地工作,因为如果调整图片大小,代码保持不变,但渐变必须随着图片改变大小。因此,要么我不能对不同大小的相同渐变使用相同的 key ,要么每次调整图片大小时都必须清除缓存。

这促使我尝试为 HashMap 创建一个复合键。稍微阅读一下 Java,我发现据我所知,它不像 C# 那样支持元组。因此,创建组合键的推荐方法是创建一个新类。所以我开始创建一个新类来表示组合键。然后我意识到我又回到了原点。如果我必须创建一个引用类型对象来表示键,lint 会在 onDraw 期间向我发出有关分配内存的警告,对吧? (或者即使没有,我也会在 onDraw 期间分配内存,这是我们试图避免的。)

我需要一些专家的建议。我是否为了优化而搬山,这更像是指导方针而不是规则,而我应该根据需要创建渐变?我是否应该使用代码作为 HashMap 键并在每次大小更改时清除缓存?字符串操作(例如子字符串)是否也需要我试图避免的内存分配? Java 支持自定义值类型吗?我是否需要编写自己的 HashMap 替代品,使其可以接受一系列值类型作为键而不分配堆内存?

最佳答案

不幸的是,没有办法(我相信你知道)来设置 LinearGradient 的大小或颜色。我认为缓存东西是最好的选择。让我澄清一些事情:

  1. 不要在每次 onDraw 时创建新的 LinearGradients

  2. 是的,子字符串分配一个新的字符串对象(有一些小的异常(exception)是空字符串 AFAIK)。由于 Java 或 C# 中无法实际更改字符串对象的内容,因此必须为字符串创建一个新对象。这就是为什么在创建字符串时建议使用 StringBuilders 的原因。另外,您似乎有 C# 背景,因此如果您还没有遇到过这种情况(6 个月后...),请记住使用 String.equals 不是==!

  3. Java 不支持自定义值类型。一切都分配在堆上。希望某些分配能够被优化掉,但这不能保证,并且显然在许多情况下不适用。

基本上:

首先,“lint”就是这样。这甚至不是警告。这只是针对您正在开发的平台的指南。随意分配抽签,但尽量避免每次都这样做。如果您需要在绘制期间创建新的 LinearGradient,请继续,但将其保存以供以后使用,这样您就不必再次创建。

其次,您可以对着色器执行一项特殊操作,以避免生成大量着色器:使用 Shader.setLocalMatrix 移动它并调整其大小。我在调整某些着色器大小时遇到​​了一些麻烦(例如,我知道它不适用于 RadialGradient),但如果您幸运的话,它可能会起作用。如果其他方法都失败,也许会退回到将新矩阵推送到 Canvas 堆栈上。

关于java - 使用 HashMap 中的复合键优化许多 LinearGradient 着色器的 onDraw,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14547946/

相关文章:

android - Android CameraX 预览质量不佳(取景器)

java - Python 代码转换为 JVM

javascript - js 内存组织 - 闭包与对象?

java - 为源服务器列出具有 UNC 路径的文件时 UI 缓慢且无响应

android - 我有一个带有回收器 View 适配器类的 Activity ,当在适配器类中单击按钮时我想刷新主要 Activity

java - 使用扫描仪读取csv时如何不读取标题行?

Mysql多重连接对self和其他表性能的影响

performance - 对于我的应用程序来说,什么是更好的选择 - CoreData 或 plist

java - 在不知道公共(public)类名的情况下编译 .java 文件

java - 为什么 ListView 需要将其容器项放在单独的布局文件中