三星Galaxy Tab出现性能问题

12
我正在制作一个2D教程,并在三星Galaxy Tab上测试了我的当前教程部分。 教程简单地随机移动默认图标并且通过点击创建一个新的移动图标。只要屏幕上有25个或更少的元素,Galaxy就可以正常运行(60fps)。当第26个元素出现时,帧速率降至25fps。将图像的大小/维度更改为较大的图像时,在第26个元素之前就达不到25fps。这是可以接受的。但在某些无法重现的元素数量上,帧会从(通常高于)10fps下降到1fps。 我尝试了:将位图变量更改为静态变量,因此不是每个元素都有自己的图像,而是都使用相同的图像。这解决了问题,但我怀疑这个解决方案是否合适。数字“25”的神奇效应表明,我只能以这种方式使用25个不同的图像。 有人知道是什么原因导致了这种性能问题吗?这是Samsung修改版Android中的错误吗? 可以通过我的示例eclipse项目进行检查。我的同事找到了一种解决方法。他从中更改了位图的加载方式。
mBitmap = BitmapFactory.decodeResource(res, R.drawable.icon);

为了

mBitmap = BitmapFactory.decodeStream(new BufferedInputStream(res.openRawResource(R.drawable.icon)));

但我们仍然不太明白为什么它会以这种方式工作...

刚在我的 Galaxy Tab 上尝试了一下,帧率似乎与你的相匹配。 - William Roe
1
在我的 Nexus S 上,当大约有 210 个元素时,它会下降到 50 帧每秒。 - William Roe
3个回答

5

嗯,我看了一下你的项目,一切看起来都很好,但我有一个关于帧率下降原因的想法。

你正在运行时分配对象。 如果你不这样做,它将使你在开始时创建所有对象,因此你应该直接注意到显著的下降(如果我的解决方案不能解决你的问题)。

话虽如此; 我不确定 对象池是否能解决你的问题,但你可以尝试。在构造函数中初始化你的对象,而不是在onTouchEvent():中进行此调用。

new Element(getResources(), (int) event.getX(), (int) event.getY())

您应该有类似于mElement.add(objectPool.allocate())的东西,其中对象池会在池中找到未使用的对象。此外,我们应该在对象池中指定一定数量的对象,从那里您可以检查是分配导致了这个错误还是其他原因。

第26个元素时,帧率降至25fps。

当您实现此功能时(如果需要),您应该直接看到帧速率下降(如果这不能解决您的问题),因为对象池将使您在开始时分配固定数量(例如,可能是100个元素?),但您在视觉上没有使用它们。
此外,在我的一个Android示例应用程序中,我使用了内存池模式(对象池)。在该示例中,我使用对象池(而不是在运行时进行分配)在onTouchEvent()上的Canvas上添加一行。在该源代码中,您可以轻松更改对象的总数并尝试自己。如果您想查看我的示例应用程序(和源代码),请写下评论,我很乐意分享,因为它还没有公开。我的注释是用瑞典语编写的,但我认为您应该能够理解,因为变量和方法是用英语编写的。:) 顺便说一下:您写道,通过使您的Bitmapstatic来删除行为已经尝试过(甚至成功)。就目前而言,您的元素具有不同的Bitmap实例,这将使您在构造新对象时每次分配一个新的Bitmap。这意味着每个对象在使用相同资源时都指向不同的Bitmapstatic是完全有效的解决方案(尽管25这个数字看起来很奇怪)。
这个Bitmap案例可以与OpenGL系统进行比较。如果有20个对象都应该使用相同的资源,则有两种可能的解决方案:它们可以指向相同的VRAM纹理,或者它们可以指向不同的VRAM纹理(就像您没有使用static的情况),但仍然是相同的资源。 编辑这是我Android的示例应用程序,演示了内存池模式。
关于您使用的BitmapFactory解决方案,它可能取决于该类的工作方式。我不确定,但我认为其中一个decode...()方法即使是相同的资源也会生成新的Bitmap。虽然这只是一个猜测,但new BufferedInputStream(res.openRawResource(R.drawable.icon))可能正在重用内存中的BufferedInputStream
在这种情况下,您应该对资源进行解码,并在Panel类中存储对它的引用,并将该引用传递到new Element(bitmapReference, ...)中。这样,您只需要分配一次,每个元素都指向内存中相同的Bitmap

如果您能分享您的示例代码,我会非常乐意查看。我尝试使用一个非常简单的对象池,首先创建了100个元素,但只显示其中一部分。随着每个触摸事件,显示的元素数量增加,即使加载了100个元素并且显示了25个元素,我也获得了60fps。第26个元素仍然会导致降至25fps。无论如何,我的同事找到了一个解决方案,并将其作为编辑添加到我的答案中。 - WarrenFaith
@WarrenFaith:我更新了我的答案,并附上了我的项目链接。我还添加了一些关于如何重复使用相同的“Bitmap”引用的信息,这样您就不需要每次创建新元素时都从“BitmapFactory”类返回一个新的“Bitmap”。 - Wroclai
谢谢分享。一般来说,我会创建一个位图缓存,将位图存储在其中,并与想要显示它的所有人共享同一实例。我认为这通常是最好的解决方案。但这有点离题,因为性能下降不应该这么快发生。至少对于25个元素来说,我不会期望出现这种情况。 - WarrenFaith
@WarrenFaith:没问题。你提到的解决方案可能是最好的。 - Wroclai

3

我已经在HTC Desire HD上尝试了您的代码,使用Android 2.2目标,在添加第20张图片后,帧率下降到无法使用。当我将相同的代码导出为Android版本2.1时,它正常运行,并可以处理超过200个实例!

我怀疑这与在2.2上创建GraphicObject类的实例有关,但不太确定...


感谢您的测试。问题是为什么。这个类并不复杂,位图只有4kb和72像素尺寸(hdpi版本)。我将在工作中尝试在不同的设备上测试样本。感谢您的反馈! - WarrenFaith
请注意,我使用了相同的设备,只是更改了目标操作系统。 - Lumis
选项卡版本是2.2,我的项目目标是2.1。将其更改为2.2(以及minSdkVersion),但没有任何变化。 - WarrenFaith
有些奇怪,因为它在针对2.1的项目中安装时,在HTC Desire HD(2.2)上运行良好。很抱歉我无法提供更多帮助。 - Lumis

1

我相信我可以为这个问题提供一些帮助。

至少在我的Galaxy S上,Gingerbread 2.3.5第一段代码将test.png加载到Bitmap中,并使用Bitmap.Config = ARGB_8888,而第二段代码则使用Bitmap.Config = RGB565进行加载。奇怪的是,虽然Gingerbread默认应该创建32位表面,但RGB565“渲染”(我对drawBitmap的本地调用进行了分析和比较)速度更快。

因此,第二个想法更适合你的整体示例,即ARGB888 Bitmap确实具有alpha通道,因此在这种情况下,渲染25个以上精灵的重叠图像可能会在alpha计算算法中创建一些瓶颈,而RGB565图像则会很好且快速。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接