Android_SurfaceView基本讲解
来源:互联网 发布:轮询调度算法 round 编辑:程序博客网 时间:2024/05/19 03:41
1. SurfaceView介绍
通常情况程序的View和用户响应都是在同一个线程中处理的,这也是为什么处理长时间事件(例如访问网络)需要放到另外的线程中去(防止阻塞当前UI线程的操作和绘制)。但是在其他线程中却不能修改UI元素,例如用后台线程更新自定义View(调用View的在自定义View中的onDraw函数)是不允许的。
如果需要在另外的线程绘制界面、需要迅速的更新界面,或者渲染UI界面需要较长的时间,这种情况就要使用SurfaceView了。SurfaceView中包含一个Surface对象,而Surface是可以在后台线程中绘制的。
如果需要在另外的线程绘制界面、需要迅速的更新界面,或者渲染UI界面需要较长的时间,这种情况就要使用SurfaceView了。SurfaceView中包含一个Surface对象,而Surface是可以在后台线程中绘制的。
SurfaceView的性质决定了其比较适合一些场景:需要界面迅速更新、对帧率要求较高的情况。
使用SurfaceView需要注意以下几点情况:
(1)SurfaceView和SurfaceHolder.Callback函数都从当前SurfaceView窗口线程中调用(一般而言就是程序的主线程)。
(2)有关资源状态要注意和绘制线程之间的同步。
(3)在绘制线程中必须先合法的获取Surface才能开始绘制内容,在SurfaceHolder.Callback.surfaceCreated() 和SurfaceHolder.Callback.surfaceDestroyed()之间的状态为合法的,在Surface类型为SURFACE_TYPE_PUSH_BUFFERS时是不合法的。
(4)额外的绘制线程会消耗系统的资源,在使用SurfaceView的时候要注意这点。
2. 使用SurfaceView
只要继承SurfaceView类并实现SurfaceHolder.Callback接口就可以实现一个自定义的SurfaceView了,SurfaceHolder.Callback在底层的Surface状态发生变化的时候通知View,SurfaceHolder.Callback具有如下的接口:
surfaceCreated(SurfaceHolder holder):当Surface第一次创建后会立即调用该函数。程序可以在该函数中做些和绘制界面相关的初始化工作,一般情况下都是在另外的线程来绘制界面,所以不要在这个函数中绘制Surface。
surfaceChanged(SurfaceHolder holder, int format, int width,int height):当Surface的状态(大小和格式)发生变化的时候会调用该函数,在surfaceCreated调用后该函数至少会被调用一次。
surfaceDestroyed(SurfaceHolder holder):当Surface被摧毁前会调用该函数,该函数被调用后就不能继续使用Surface了,一般在该函数中来清理使用的资源。
通过SurfaceView的getHolder()函数可以获取SurfaceHolder对象,Surface 就在SurfaceHolder对象内。虽然Surface保存了当前窗口的像素数据,但是在使用过程中是不直接和Surface打交道的,由SurfaceHolder的Canvas.lockCanvas()或则Canvas.lockCanvas(Rect dirty)函数来获取Canvas对象,通过在Canvas上绘制内容来修改Surface中的数据。如果Surface不可编辑,或者尚未创建调用该函数会返回null,在 unlockCanvas() 和 lockCanvas()中Surface的内容是不缓存的,所以需要完全重绘Surface的内容,为了提高效率只重绘变化的部分则可以调用lockCanvas(Rect dirty)函数来指定一个dirty区域,这样该区域外的内容会缓存起来。在调用lockCanvas函数获取Canvas后,SurfaceView会获取Surface的一个同步锁直到调用unlockCanvasAndPost(Canvas canvas)函数才释放该锁,这里的同步机制保证在Surface绘制过程中不会被改变(被摧毁、修改)。
通过SurfaceView的getHolder()函数可以获取SurfaceHolder对象,Surface 就在SurfaceHolder对象内。虽然Surface保存了当前窗口的像素数据,但是在使用过程中是不直接和Surface打交道的,由SurfaceHolder的Canvas.lockCanvas()或则Canvas.lockCanvas(Rect dirty)函数来获取Canvas对象,通过在Canvas上绘制内容来修改Surface中的数据。如果Surface不可编辑,或者尚未创建调用该函数会返回null,在 unlockCanvas() 和 lockCanvas()中Surface的内容是不缓存的,所以需要完全重绘Surface的内容,为了提高效率只重绘变化的部分则可以调用lockCanvas(Rect dirty)函数来指定一个dirty区域,这样该区域外的内容会缓存起来。在调用lockCanvas函数获取Canvas后,SurfaceView会获取Surface的一个同步锁直到调用unlockCanvasAndPost(Canvas canvas)函数才释放该锁,这里的同步机制保证在Surface绘制过程中不会被改变(被摧毁、修改)。
当在Canvas中绘制完成后,调用函数unlockCanvasAndPost(Canvas canvas)来通知系统Surface已经绘制完成,这样系统会把绘制完的内容显示出来。为了充分利用不同平台的资源,发挥平台的最优效果可以通过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对象了。
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只在SurfaceHolder.Callback.surfaceCreated() 和 SurfaceHolder.Callback.surfaceDestroyed()调用之间是可用的,其他时间是得不到它的Canvas对象的(null)。
3. SurfaceView和View的区别
SurfaceView和View最本质的区别在于,surfaceView是在一个新起的单独线程中可以重新绘制画面,而View必须在UI的主线程中更新画面。
在UI的主线程中更新画面可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。当使用SurfaceView时,由于是在新的线程中更新画面所以不会阻塞UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要SurfaceView中的Thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。
所以基于以上,根据游戏特点,一般分成两类:
(1)被动更新画面的。比如棋类,用View就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为在这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。
(2)主动更新画面的。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞UI主线程。所以显然view不合适,需要surfaceView来控制。
简单代码示例:
public class BoomFlowerView extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder mHolder; private DrawThread mDrawThread; public BoomFlowerView(Context context) { super(context); init(); } public BoomFlowerView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public BoomFlowerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mHolder = getHolder(); mDrawThread = new DrawThread(); mHolder.addCallback(this); } @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { mDrawThread.start(); } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { } class DrawThread extends Thread{ @Override public void run() { super.run(); Paint mPaint = new Paint();//实例化画笔 AssetManager manager = getResources().getAssets(); int i = 1; while (true){ String fileName = null; Canvas canvas = mHolder.lockCanvas();//锁定画布 canvas.drawColor(Color.BLACK); InputStream is = null; if(i<=9){ fileName= "loading000"+i+".png"; }else { fileName = "loading00"+i+".png"; } try { is = manager.open(fileName); Bitmap bitmap = BitmapFactory.decodeStream(is); if(canvas!=null){ canvas.drawBitmap(bitmap,200,400,mPaint); mHolder.unlockCanvasAndPost(canvas); } } catch (IOException e) { e.printStackTrace(); }finally { if(is!=null){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } i++; if(i>26){ i = 1; } } } }}
public class CricleView extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder mSurfaceHolder; private DrawThread mDrawThread; public CricleView(Context context) { super(context); initView(); } public CricleView(Context context, AttributeSet attrs) { super(context, attrs); initView(); } public CricleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(); } private void initView() { mSurfaceHolder = getHolder(); mDrawThread = new DrawThread();//绘制线程 mSurfaceHolder.addCallback(this); } //创建的时候开始绘制 @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { mDrawThread.start(); } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { } //子线程 用来绘制 图的 class DrawThread extends Thread{ @Override public void run() { super.run(); Paint paint = new Paint();//画笔 paint.setColor(Color.GREEN);//画笔的颜色 paint.setStrokeWidth(5);//画笔的宽度 paint.setAntiAlias(true);//画笔的抗锯齿 int rales = 0; while (true){ if(rales > 150){ rales = 0; } rales+=5; Canvas canvas = mSurfaceHolder.lockCanvas();//锁定一个画布 if(canvas!=null){ canvas.drawColor(Color.RED);//设置画布的颜色 canvas.drawLine(20,20,200,200,paint); canvas.drawCircle(200,200,rales,paint); mSurfaceHolder.unlockCanvasAndPost(canvas); } } } }}
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }}
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="alice.bw.com.surfaceviewdemo.MainActivity"> <alice.bw.com.surfaceviewdemo.CricleView android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="gone" /> <alice.bw.com.surfaceviewdemo.BoomFlowerView android:layout_width="match_parent" android:layout_height="match_parent"/></RelativeLayout>
阅读全文
0 0
- Android_SurfaceView基本讲解
- android_SurfaceView 画图
- android_SurfaceView 画图
- OpenCL基本讲解
- 基本动态规划讲解
- matlab基本绘图讲解
- JDBC基本步骤讲解
- Android基本命令讲解
- httpclient基本用法讲解
- Service基本讲解
- UIScrollable的基本讲解
- SpringMvc基本讲解
- CSS基本样式讲解
- mysql 基本讲解
- jdbc 基本讲解
- tablayout基本讲解
- Nginx基本配置讲解
- ViewDragHelper基本方法讲解
- 男子疯狂买入却只落得“一地鸡毛”,跟风投资十年努力破产
- [喵咪BELK实战(1)]浅谈日志的重要性以及介绍BELK
- Javac编译过程笔记
- [译]React v16(新特性)
- replace与replaceAll遇到转义字符时的区别
- Android_SurfaceView基本讲解
- 西瓜视频或小米手机,有一个公司做恶了
- mini记事本
- Webpackplugins
- 使用for循环和%求取素数
- 如何在Windows系统中设置Python程序定时运行
- [喵咪BELK实战(2)] elasticsearch+kibana搭建
- 只是简单的一个集成GreenDao的博客
- 2017最后一场|运营总监修炼之道深圳站12月课程火热报名中