在一般情况下,应用程序的View都是在相同的GUI线程中绘制的。这个主应用程序线程同时也用来处理所有的用户交互(例如按钮单击或者文本输入)。
对于一个View的onDraw()方法,不能够满足将其移动到后台线程中去。因为从后台线程修改一个GUI元素会被显式地禁止的。而SurfaceView,可以在主线程之外的线程中向屏幕绘图。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。
当需要快速,主动地更新View的UI,或者当前渲染代码阻塞GUI线程的时间过长的时候,SurfaceView就是解决上述问题的最佳选择。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main
UI thread。所以显然view不合适,需要surfaceView来控制。
被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于onTouch 来更新,可以直接使用
invalidate。因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。
SurfaceView使用的方式与任何View所派生的类都是完全相同的。可以像其他View那样应用动画,并把它们放到布局中。
SurfaceView 有一个原则,所有的绘图工作必须得在Surface
被创建之后才能开始。可以被直接复制到显存从而显示出来,这使得显示速度会非常快,而在Surface
被销毁之前必须结束。所以Callback 中的surfaceCreated 和surfaceDestroyed
就成了绘图处理代码的边界。
需要重写的方法
(1)public void surfaceChanged(SurfaceHolder
holder,int format,int width,int height){}
//在surface的大小发生改变时激发
(2)public void surfaceCreated(SurfaceHolder
holder){}
//在创建时激发,一般在这里调用画图的线程。
(3)public void surfaceDestroyed(SurfaceHolder
holder) {}
//销毁时激发,一般在这里将画图的线程停止、释放。
一个典型的SurfaceView
设计模型包括一个由Thread所派生的类,它可以在创建的时候接收对当前的SurfaceHolder的引用,在Thread的run方法中,可以由该引用可以得到布局中SurfaceView的canvas,
并更新它。
package dhb.test;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MysurfaceTestActivity extends Activity {
int count =
0; @Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyView(this));
}
public
void doDraw(Canvas c){
c.drawColor(Color.BLACK);//设置画布背景颜色
Paint p = new Paint(); //创建画笔
p.setColor(Color.WHITE);
Rect r = new Rect(100, 50, 300, 250);
c.drawRect(r, p);
c.drawText("这是第"+(count)+"秒", 100, 310, p);
}
//视图内部类
class
MyView extends SurfaceView implements SurfaceHolder.Callback
{
private SurfaceHolder holder;
private MyThread myThread;
private MyDrawThread myDrawThread;
public MyView(Context context) {
super(context);
// TODO Auto-generated constructor stub
holder = this.getHolder();
holder.addCallback(this);
myThread = new MyThread (); //创建一个数据更新线程
myDrawThread = new MyDrawThread (holder);//创建一个绘图线程
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int
width,
int height) {
// TODO Auto-generated method stub
System.out.println("surfaceChanged");
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
System.out.println("surfaceCreated");
myDrawThread.isRun = true;
myDrawThread.start();
myThread.isRun = true;
myThread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
myDrawThread.isRun = false;
myThread.isRun = false;
System.out.println("surfaceDestroyed");
}
}
//线程内部类
//数据更新线程
class
MyThread extends Thread
{
public boolean isRun;
public MyThread ()
{
isRun = true;
}
@Override
public void run()
{
System.out.println("MyThread - run");
while(isRun)
{
count++;
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
//
TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//创建一个绘图线程
class
MyDrawThread extends Thread
{
private SurfaceHolder holder;
public boolean isRun ;
public MyDrawThread(SurfaceHolder holder)
{
this.holder =holder;
isRun = true;
}
@Override
public void run()
{
System.out.println("MyDrawThread - run");
while(isRun)
{
Canvas c = null;
try
{
synchronized (holder)
{
c =
holder.lockCanvas();//锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。
doDraw(c);
Thread.sleep(1000);//睡眠时间为1秒
}
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
finally
{
if(c!= null)
{
holder.unlockCanvasAndPost(c);//结束锁定画图,并提交改变。
}
}
}
}
} }