原博客不更新 http://write.blog.csdn.net/postlist ,以后内容都会在这里写
在开始本文之前先看一段Log
“Skipped 47 frames! The application may be doing too much work on its main thread”
这个警告大多数是在自定义View时产生的,而其中在绘制过程中处理逻辑太多、刷新数据量比较大是主要原因
因为逻辑和刷新的数据一般和产品的效果或逻辑有关,优化的空间有限,如果对产品流程性要求很高就需要用新的东东来实现了。Android提供了SurfaceView就是来处理这种情形的。
View通过刷新来重绘视图,Android系统通过发出VSYNC信号来进行屏幕绘制,刷新时间间隔为16ms。如果18ms内View完成了你所须要执行的操作,那么在视觉上就不会参数卡顿;但是当执行逻辑或处理数据较多时,特别是需要频繁刷新的界面上,就会阻塞主线程导致画面卡顿。如:相机取景、视频播放、游戏界面绘制。普通应用最容易遇到的场景,在获取网络数据时加载动画,数据解析完毕隐藏动画显示UI。如果解析的数据量很大,在数据返回到解析完毕情况动画就会卡顿一下。
SurfaceView和View的主要区别:
- View主要适用于主动更新,SurfaceView主要适用于被动、频繁更新
- View在主线程中对画面进行刷,SurfaceView通常会通过一个子线程进行页面刷新
- View在绘制是没有使用双缓冲机制,而SurfaceView在底层实现机制中已经实现了双缓冲机制
因为SurfaceView使用子线程更新页面,因此在有交互场景是会带来事件同步问题
SurfaceHolder的setType函数来设置绘制的类型,参数如下:
SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface
SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface
SURFACE_TYPE_GPU:适用于GPU加速的Surface
SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包含原生数据,Surface用到的数据由其他对象提供,在Camera图像预览中就使用该类型的Surface,有Camera负责提供给预览Surface数据,这样图像预览会比较流畅。如果设置这种类型则就不能调用lockCanvas来获取Canvas对象了
下面是标准的SurfaceView的使用模板
class MyView extends SurfaceView implements SurfaceHolder.Callback,Runnable{
boolean isRunning;
SurfaceHolder holder;
Canvas canvas;
public MyView(Context context) {
super(context);
initView();
}
//初始化
private void initView()
{
// TODO Auto-generated constructor stub
holder = getHolder();
holder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);
}
//SurfaceView创建
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
isRunning = true;
Thread t=new Thread(this);
t.start();
}
//SurfaceView改变
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
//SurfaceView销毁
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
isRunning = false;
}
// Runnable接口,Run方法的实现
@Override
public void run() {
while (isRunning) {
onDraw();
}
}
//绘制内容方法
@Override
protected void onDraw() {
try {
canvas = holder.lockCanvas();
//draw something
} catch (InterruptedException e) {
} finally{
//确保每次都能将内容提交
if(canvas != null)
{
holder.unlockCanvasAndPost(canvas);
}
}
}
}
下面来用SurfaceView实现二个具体的例子,一个是根据手势绘制内容,一个是播放视频
- 手势的绘制
下面是代码
public class SurfaceTouchView extends SurfaceView implements SurfaceHolder.Callback,Runnable{
//SurfaceHolder
private SurfaceHolder mHolder;
//用户绘制的Canvas
private Canvas mCanvas;
//子线程的标志位
private boolean mIsRunning;
//保存手指移动路径
private Path mPath;
private Paint mPaint;