在J2ME应用程序中加载图像的标准方法是使用Image.createImage方法,推荐的图像格式为PNG。
现在,J2ME规范没有对此方法的实现或Image的内存表示形成任何限制,因此,每个供应商都有不同的实现。
特别是摩托罗拉有这个非常糟糕的实现,其中PNG在创建图像时被完全解码为ARGB字节数组。这意味着尺寸为176x208的8K png占用大约170K的峰值存储器,而Image对象本身使用的内存大约为145K!在其他手机上,如诺基亚,索尼爱立信等,相同的图像只需要大约16K加载和存储在内存中。我不知道他们使用什么智能优化,但出于一些不可理解的原因,摩托罗拉的JVM没有。
这对我的J2ME应用程序造成了严重破坏,因此在摩托罗拉手机上运行它的版本几乎是不可能的。我尝试了各种解决方法,例如使用图像的gzip的ARGB字节数组并在绘制期间放气,但这会导致油漆减速10倍!
有人知道这个问题的解决方法吗?用于J2ME的开源PNG图像解码器,具有摩托罗拉所缺乏的智能?或者是否可以对PNG图像进行某些操作以减少其内存占用? (我目前使用的是索引模式PNG)任何指针都是受欢迎的。
Gowri
答案 0 :(得分:3)
索尼爱立信的一件事。不要给他们这么多的功劳。在加载图像时,它们也会占用(image_width x image_height x bytes_per_pixel)内存。
来自SE J2ME开发人员文档,“所有图像都以16位/像素RGB格式存储在手机存储器中,可能是每像素1位或8位alpha通道。 “所以,至少2个字节。不同之处在于,索尼爱立信手机(我不能代表诺基亚)有一个单独的内存块用于在堆中加载图像之前首先填充的图像(您可以通过使用Runtime.getRuntime()包装加载来看到这一点.freeMemory ()...堆大小将仅增加几个字节,这是新对象的大小。
这并不是在为摩托罗拉辩护,因为我确实把我的麻烦从SE手机移植到了摩托罗拉,但这并不是因为SE能够找到一种以更加优化的方式将图像存储在堆中的方法。摩托罗拉只是将所有东西都存储在堆中,这就是你跑得更快的原因。
较小的图像是一个好主意,不仅在解码器部分,而且从堆碎片的角度来看。它将允许图像适合较小的内存块而不是大的连续块。
答案 1 :(得分:1)
嗯,就我所看到的方式而言,如果在创建图像时所有图像格式都立即解码为ARGB数组,那么您唯一能做的就是创建用于显示的内存量的上限屏幕上的东西。
您可以创建一个图像缓存,该缓存将知道每个图像用于该特定设备的堆内存量,加载和卸载图像是否需要它们。当然,这意味着依赖Grabage Collector可能会让您的应用程序保持响应。
高速缓存管理可能需要在专用线程中进行。
如果您的应用程序屏幕足够静态而不需要太多动画,那么在任何给定时间只保留一个屏幕加载的图像都可以工作。
还要记住,MIDP Canvas通常不会重置自己。如果您使用两个不同的Canvas.paint()调用在屏幕的2个不同区域绘制2个不同的图像,那么您应该能够在实际的图像对象被垃圾收集后很长时间内显示两个图像。在他们上面画任何东西。
从纯粹的商业角度来看,您需要能够告诉您的客户,某些手机只有Java的实现非常糟糕,以至于您不会支持它们。
答案 2 :(得分:0)
PNG往往很臃肿。
为什么不改用gif。
http://www.ddj.com/mobile/184406435;jsessionid=SBUQN2ECITM5OQSNDLOSKHSCJUNN2JVN?_requestid=76071
答案 3 :(得分:0)
摩托罗拉开发者论坛建议您将较大的图像缩小到较小的条带并一次性加载这些较小的条带而不是整个大图像。请注意,不会减少图像的内存占用量。这仍然需要所有条带的总和(宽度*高度*每像素字节数)。但它确实减少了解码png图像并加载它所需的内存。这就是我现在正在做的事情。它帮助了一些人。但整体内存使用仍然是一个问题。
答案 4 :(得分:0)
更好的解决方案是将ARGB存储为数据(使用某种索引来压缩它),具有更改调色板等优点/没有PNG标头/。而不是存储不同的PNG图像,并使用createImage函数来创建图像。
答案 5 :(得分:0)
减少png图像的一种方法是通过png gauntlet之类的程序运行它们 减少它的大小。