(ps:粗斜体表示引导方案逐步进化的关键点)
SurfaceView逐帧解析 & 帧复用
简单回顾下上一篇的内容:原生帧动画在播放前解析所有帧,对内存压力大。SurfaceView
可以精细地控制帧动画每一帧的绘制,在每一帧绘制前才解析当前帧,且解析后续帧时复用前帧内存空间。遂整个过程在内存只申请了一帧图片大小的空间。下面罗列了一些关键代码:
基类:定义绘制框架
public abstract class BaseSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
…
//绘制线程
private HandlerThread handlerThread;
private Handler handler;
@Override
public void surfaceCreated(SurfaceHolder holder) {
startDrawThread();
}
private void startDrawThread() {
handlerThread = new HandlerThread(“SurfaceViewThread”);
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
handler.post(new DrawRunnable());
}
private class DrawRunnable implements Runnable {
@Override
public void run() {
try {
canvas = getHolder().lockCanvas();
//绘制一帧,包括解码+绘制帧
onFrameDraw(canvas);
} catch (Exception e) {
e.printStackTrace();
} finally {
getHolder().unlockCanvasAndPost(canvas);
onFrameDrawFinish();
}
//若onFrameDraw()执行超时,会导致下一帧的绘制被推后,预定的帧时间间隔不生效
handler.postDelayed(this, frameDuration);
}
}
protected abstract void onFrameDraw(Canvas canvas);
}
//帧动画绘制类:将绘制内容具体化为一张Bitmap
public class FrameSurfaceView extends BaseSurfaceView {
…
private BitmapFactory.Options options;
@Override
protected void onFrameDraw(Canvas canvas) {
clearCanvas(canvas);
if (!isStart()) {
return;
}
if (!isFinish()) {
//绘制一帧
drawOneFrame(canvas);
} else {
onFrameAnimationEnd();
}
}
private void drawOneFrame(Canvas canvas) {
//解析帧
frameBitmap = BitmapFactory.decodeResource(getResources(), bitmaps.get(bitmapIndex), options);
//复用帧
options.inBitmap = frameBitmap;
//绘制帧
canvas.drawBitmap(frameBitmap, srcRect, dstRect, pa