我正在动态壁纸拍摄动画。这是代码。它几乎遵循CubeWallpaper演示:
void drawFrame() {
final SurfaceHolder holder = getSurfaceHolder();
final BufferedInputStream buf;
final Bitmap bitmap, rbitmap;
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
try {
buf = new
BufferedInputStream(assets.
open(folder+"/"
+imageList[ilen++])
);
bitmap = BitmapFactory.
decodeStream(buf);
rbitmap = Bitmap.createBitmap
(bitmap,
0,0,imageWidth,imageHeight,
transMatrix,false);
c.drawBitmap(rbitmap,
paddingX,
paddingY,
null);
if ( ilen >= imageCount ) ilen=0;
}
catch (Exception e) { e.printStackTrace(); }
}
} finally {
if (c != null) holder.unlockCanvasAndPost(c);
}
// Reschedule the next redraw
mHandler.removeCallbacks(mDrawCube);
if (mVisible) {
mHandler.postDelayed(mDrawCube, fps);
}
}
其中“transMatrix”是之前预定义的缩放和旋转矩阵。
它应该以30fps渲染,但当然不会那样做。我最初的猜测是BufferedInputStream是一个因素。我应该缓存其中的一些,因为我和Bitmaps一起使用。但任何其他想法?我是否必须使用OpenGL黑客进行动态壁纸?
答案 0 :(得分:4)
是的,BufferedInputStream
和BitmapFactory
确实不应该在drawFrame()
。你在每一帧上加载和创建资源,这是一个巨大的浪费。就像你说的那样,事先尽可能多地缓存,如果你发现在绘图过程中需要加载更多,请使用一个单独的线程来做到这一点,这样就不会减慢绘图速度。
答案 1 :(得分:3)
我遇到了同样的问题:在动态壁纸的背景下慢画布渲染。
我同意其他人说你在渲染时不应该做任何重的cpu / io特别是在UI线程上加载图像。
但是还有一件事需要注意。您在渲染帧后请求重绘(mHandler.postDelayed(...))。如果你想要30 fps并因此你要求重绘(1000/30)33ms那么它不会导致每秒30帧。为什么呢?
让我们假设将所有东西渲染到画布需要28ms。完成后,您要求在33毫秒后重绘。也就是说,重绘之间的时间间隔为61毫秒,相当于每秒16帧。
您有两种方法可以解决它:
1)将mHandler.postDelayed(...)代码放到drawFrame(...)方法的开头。这似乎没问题,但它有一些缺点:如果你的实际FPS非常接近实际设备上的最大可能FPS - 换句话说UI线程一直忙着你的画布渲染 - 那么就没有时间了UI线程做其他事情。它并不一定意味着你的LWP或主屏幕会滞后但你(你的LWP)可能会开始错过一些触摸事件(就像我的LWP那样)。
2)更好的解决方案是在创建曲面时启动一个单独的线程,并将其引用传递给SurfaceHolder。在这个单独的线程中进行渲染。此线程中的render方法如下所示:
private static final int DESIRED_FPS = 25;
private static final int DESIRED_PERIOD_BETWEEN_FRAMES_MS = (int) (1000.0 / DESIRED_FPS + 0.5);
@Override
public void run() {
while (mRunning) {
long beforeRenderMs = SystemClock.currentThreadTimeMillis();
// do actual canvas rendering
long afterRenderMs = SystemClock.currentThreadTimeMillis();
long renderLengthMs = afterRenderMs - beforeRenderMs;
sleep(Math.max(DESIRED_PERIOD_BETWEEN_FRAMES_MS - renderLengthMs, 0));
}
}