我正在编写我的第一个 Android 应用程序(也是过去 15 年来我的第一个 Java 应用程序)。它采用编码字符串并将代码转换为绘图操作。一些代码代表渐变定义,这就是我的问题所关心的。
如果我理解正确,尝试在 onDraw 函数(我的扩展 View 类中的覆盖)期间创建任何类型的新对象将导致 lint 输出警告,提示在 onDraw 期间缓存对象并且从不分配新对象。所以我决定尝试对代码字符串定义的所有渐变进行缓存。这样,如果您以相同的尺寸重新绘制相同的代码,则不必重新分配该代码定义的渐变。
在尝试定义 HashMap 的键结构时遇到了问题,我认为这是缓存的最佳结构。如果我可以简单地使用将渐变定义为键的代码 fragment (字符串),那就太好了,但我认为这不会很好地工作,因为如果调整图片大小,代码保持不变,但渐变必须随着图片改变大小。因此,要么我不能对不同大小的相同渐变使用相同的 key ,要么每次调整图片大小时都必须清除缓存。
这促使我尝试为 HashMap
创建一个复合键。稍微阅读一下 Java,我发现据我所知,它不像 C# 那样支持元组。因此,创建组合键的推荐方法是创建一个新类。所以我开始创建一个新类来表示组合键。然后我意识到我又回到了原点。如果我必须创建一个引用类型对象来表示键,lint 会在 onDraw 期间向我发出有关分配内存的警告,对吧? (或者即使没有,我也会在 onDraw 期间分配内存,这是我们试图避免的。)
我需要一些专家的建议。我是否为了优化而搬山,这更像是指导方针而不是规则,而我应该根据需要创建渐变?我是否应该使用代码作为 HashMap
键并在每次大小更改时清除缓存?字符串操作(例如子字符串)是否也需要我试图避免的内存分配? Java 支持自定义值类型吗?我是否需要编写自己的 HashMap
替代品,使其可以接受一系列值类型作为键而不分配堆内存?
最佳答案
不幸的是,没有办法(我相信你知道)来设置 LinearGradient 的大小或颜色。我认为缓存东西是最好的选择。让我澄清一些事情:
不要在每次 onDraw 时创建新的 LinearGradients
是的,子字符串分配一个新的字符串对象(有一些小的异常(exception)是空字符串 AFAIK)。由于 Java 或 C# 中无法实际更改字符串对象的内容,因此必须为字符串创建一个新对象。这就是为什么在创建字符串时建议使用 StringBuilders 的原因。另外,您似乎有 C# 背景,因此如果您还没有遇到过这种情况(6 个月后...),请记住使用
String.equals
不是==
!Java 不支持自定义值类型。一切都分配在堆上。希望某些分配能够被优化掉,但这不能保证,并且显然在许多情况下不适用。
基本上:
首先,“lint”就是这样。这甚至不是警告。这只是针对您正在开发的平台的指南。随意分配抽签,但尽量避免每次都这样做。如果您需要在绘制期间创建新的 LinearGradient,请继续,但将其保存以供以后使用,这样您就不必再次创建。
其次,您可以对着色器执行一项特殊操作,以避免生成大量着色器:使用 Shader.setLocalMatrix
移动它并调整其大小。我在调整某些着色器大小时遇到了一些麻烦(例如,我知道它不适用于 RadialGradient),但如果您幸运的话,它可能会起作用。如果其他方法都失败,也许会退回到将新矩阵推送到 Canvas 堆栈上。
关于java - 使用 HashMap 中的复合键优化许多 LinearGradient 着色器的 onDraw,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14547946/