我最近开始编写Android的2D应用程序(纯Java代码)。我对Java和Android编程没有太多经验。
我的java代码性能非常差。看起来很奇怪,因为我正在运行的手机是三星Glaxy S2(ARM Cortex A9 1.2Ghz双核心),应该会给出更好的效果。
我的应用程序是动态壁纸。我正在使用android.graphics库来绘制我的图像。我正在运行一个自定义场景图代码来管理我的转换和边界矩形层次结构(我也在进行可见性测试)。
根据DDMS探查器(方法跟踪),我的渲染循环执行30 - 45ms(不确定为什么它变化太大,因为我的场景不会从捕获变为捕获)。
位图绘制大约需要15ms。剩余时间(15 - 30ms)花费遍历场景图来更新转换并检查可见性。
我在场景图中有12个节点和11个可绘制对象!
我真的不明白为什么代码运行得这么慢。从DDMS我无法识别代码的任何特定部分是瓶颈。我没有在代码中分配任何临时对象,除了大量的迭代器,我无法找到摆脱的方法。
似乎只是调用方法需要很多时间。 30ms很多用于遍历12个节点并将它们的矩阵相乘并扩展一些范围。
1.6分钟用于分选4-5个对象???
我必须做一些非常愚蠢的事情!任何建议都将受到高度赞赏!private final LinkedList<SceneNode> m_children = new LinkedList<SceneNode>();
private final LinkedList<Drawable> m_drawables = new LinkedList<Drawable>();
public void update(boolean updateChildren)
{
updateDerivedTransform();
if (updateChildren)
{
for (SceneNode child : m_children)
{
child.update(updateChildren);
}
}
updateBoundingRect();
}
protected void updateDerivedTransform()
{
if (m_parent != null)
{
m_derivedTransform.setConcat(m_parent.m_derivedTransform, m_transform);
}
else
{
m_derivedTransform.set(m_transform);
}
}
public void updateBoundingRect()
{
m_boundingRect.setEmpty();
for (Drawable drawable : m_drawables)
{
m_boundingRect.union(drawable.getTransformedBoundingRect());
}
for (SceneNode child : m_children)
{
m_boundingRect.union(child.m_boundingRect);
}
}
public void findVisibleObjects(RectF viewRect, DrawQueue queue, boolean includeChildren, boolean addNodes)
{
float x = m_boundingRect.left;
float y = m_boundingRect.top;
float w = m_boundingRect.right;
float h = m_boundingRect.bottom;
if (viewRect.contains(x, y, w, h) || viewRect.intersects(x, y, w, h))
{
queue.getContainer().addAll(m_drawables);
for (SceneNode child : m_children)
{
child.findVisibleObjects(viewRect, queue, includeChildren, addNodes);
}
}
}
非常感谢你的帮助!
答案 0 :(得分:2)
以下是一些没有看到您的代码的想法。
你的逻辑分为两个线程吗?您应该有一个仅以当前状态绘制壁纸的线程。然后让这个线程尽可能快地运行,这样你的帧速率就越高。在第二个线程中,您应该根据应用程序启动后经过的时间来处理更新壁纸的所有逻辑。
这有两个目的。它将逻辑抽象为两个不同的部分,使其更容易进行错误检查和优化。这也意味着如果计算量特别大,你的帧速率不会下降。
如果我们能够看到代码,那么我们就可以指出代码中的点效率特别低,可以进行改进。
答案 1 :(得分:0)
我发现方法之间的反弹和循环内的if语句都会导致较低规格的设备出现性能问题。
答案 2 :(得分:0)
Java上有很多每次调用的开销,特别是Android的实现(在dalvik中)。尽量减少你在课堂上进行的通话次数。
作为次要优化(当你到达那一点时),而不是使用LinkedList
,考虑使用ArrayList
(或者甚至是静态大小的数组,如果你不经常添加元素)并为你的循环执行此操作:
final int count = m_drawables.size();
for (int i = 0; i < count; i++) {
Drawable drawable = m_drawables.get(i);
//...
}
Android的JIT在优化容器迭代器循环(for (Foo foo : fooContainer)
)方面非常糟糕,我通过将它们转换为传统的计数循环找到了相当大的加速。如果你看一下代码反汇编,这样的循环实际上变成了大量的方法调用,迭代器有很多对象创建和销毁。它们便于代码节省而不是性能(尽管希望未来对Dalvik JIT的改进将有助于实现这一目标。)
您可能还发现,绘制对象比在绘制对象之前尝试确定哪些对象可见更快。