关闭

SurfaceView

155人阅读 评论(0) 收藏 举报

概述


普通view的UI是在程序主线程中绘制的,如果绘制过程复杂(比如游戏画面,摄像头预览),可能会导致主线程ANR,surfaceview可以很好的解决这个问题,surfaceview在一个独立的线程中做绘制工作。
想要代码的少年可直奔代码2.

官方介绍

Provides a dedicated drawing surfaceembedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screen

The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed. The view hierarchy will take care of correctly compositing with theSurface any siblings of the SurfaceView that would normally appear on top of it. This can be used to place overlays such as buttons on top of the Surface,though note however that it can have an impact on performance since a full alpha-blended composite will be performed each time the Surface changes.

Access to the underlying surface is provided via the SurfaceHolder interface, which can be retrieved by calling getHolder().

The Surface will be created for you while the SurfaceView's window is visible; you should implement surfaceCreated(SurfaceHolder) and surfaceDestroyed(SurfaceHolder) to discover when the Surface is created and destroyed as the window is shown and hidden.

One of  the purposes of this class is to provide a surface in which a secondary thread can  render in to the screen. If you are going to use it thisway, you need to be aware of some threading semantics:

•All SurfaceView and SurfaceHolder.Callback methods will be called from the thread running the SurfaceView's window (typically the main thread of the application). They thus need to correctly synchronize with any state that is also touched by the drawing thread. 
•You must ensure that the drawing thread only touches the underlying Surface while it is valid -- between SurfaceHolder.Callback.surfaceCreated() and SurfaceHolder.Callback.surfaceDestroyed(). 
个人翻译
    SurfaceView
View的一个子类,专门用于绘制。你可以控制这个Surface的格式和尺寸。Surfaceview控制这个Surface的绘制位置。
      surface
是纵深排序(Z-ordered)的,这表明它总在surfaceview窗口的后面。surfaceview提供了一个可见区域,只有在这个可见区域内surface部分内容才可见,可见区域外的部分不可见。(可以认为surfacesurfaceview2层,surface上有很多内容,但是看不到,只有surfaceview指定的部分可以被看到。Surfaceview相当于是surface对外开出的一个窗口)surface的排版显示受到视图层级关系的影响,surfaceview的兄弟视图会在顶端正常显示。这意味者surface的内容会被surfaceview的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)(例如,文本和按钮等控件)。注意,如果surface上面有透明控件,那么它的每次变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。
       
你可以通过SurfaceHolder接口访问这个surfacegetHolder()方法可以得到这个接口。
        surfaceview
窗口可见时,surface被创建;surfaceview隐藏前,surface被销毁。这样能节省资源。你可以重载surfaceCreated(SurfaceHolder) surfaceDestroyed(SurfaceHolder),能发现这2个函数是在窗口显示和隐藏的时候调用的。

surfaceview这个类的作用就是为了支持第二个绘图线程来渲染图像至屏幕。我们暂时称surface中专门用于绘图的线程为渲染线程,还有一个线程是主线程。
     
应注意:
        1> 
所有SurfaceViewSurfaceHolder.Callback的方法都应该在UI线程里调用,一般来说就是应用程序主线程。渲染线程所要访问的各种变量应该作同步处理。
        2> 
由于surface可能被销毁,它只在SurfaceHolder.Callback.surfaceCreated()SurfaceHolder.Callback.surfaceDestroyed()之间有效,所以要确保渲染线程访问的是合法有效的surface


MVC

Surface、SurfaceView和SurfaceHolder实质上就是广为人知的MVC,即Model-View-Controller。Model就是模型的意思,或者说是数据模型,或者更简单地说就是数据,也就是这里的Surface;View即视图,代表用户交互界面,也就是这里的SurfaceView;SurfaceHolder很明显可以理解为MVC中的Controller(控制器)。


定义

可以直接从内存或者DMA等硬件接口取得图像数据,是个非常重要的绘图容器。

它的特性是:可以在主线程之外的线程中向屏幕绘图上。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。在游戏开发中多用到SurfaceView,游戏中的背景、人物、动画等等尽量在画布canvas中画出。

实现

首先继承SurfaceView并实现SurfaceHolder.Callback接口
使用接口的原因:因为使用SurfaceView 有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始(Surface—表面,这个概念在 图形编程中常常被提到基本上我们可以把它当作显存的一个映射,写入到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并实现SurfaceHolder.Callback接口 ----> SurfaceView.getHolder()获得SurfaceHolder对象 ---->SurfaceHolder.addCallback(callback)添加回调函数---->SurfaceHolder.lockCanvas()获得Canvas对象并锁定画布----> Canvas绘画 ---->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)结束锁定画图,并提交改变,将图形显示。


SurfaceHolder

这里用到了一个类SurfaceHolder,可以把它当成surface的控制器,用来操纵surface。处理它的Canvas上画的效果和动画,控制表面,大小,像素等。
几个需要注意的方法:
(1)、abstract void addCallback(SurfaceHolder.Callback callback);
// 给SurfaceView当前的持有者一个回调对象。
(2)、abstract Canvas lockCanvas();
// 锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。
(3)、abstract Canvas lockCanvas(Rect dirty);
// 锁定画布的某个区域进行画图等..因为画完图后,会调用下面的unlockCanvasAndPost来改变显示内容。
// 相对部分内存要求比较高的游戏来说,可以不用重画dirty外的其它区域的像素,可以提高速度。
(4)、abstract void unlockCanvasAndPost(Canvas canvas);
// 结束锁定画图,并提交改变。

代码1

这个代码来自http://www.cnblogs.com/xuling/archive/2011/06/06/android.html,我稍微改了下,原代码在启动程序之后按home键再切回来会崩溃,原因是这个过程不调用OnCreate,那MyView对象不变化,再次调用到surfaceCreated,会导致同一个线程多次start。我把

setContentView(new MyView(this));放入onResume中就可以了,这样每次都重新new一个MyView,new一个线程

package com.example.a;



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 MainActivity extends Activity {

    MyView mMyView;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mMyView=new MyView(this);
    }
    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        setContentView(mMyView);
        super.onResume();
        
    }
    //视图内部类
    class MyView extends SurfaceView implements SurfaceHolder.Callback
    {
        private MyThread myThread; 
        public MyView(Context context) {
            super(context);
            // TODO Auto-generated constructor stub
            SurfaceHolder holder = this.getHolder();
            holder.addCallback(this);
           // holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
           
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height) {
            // TODO Auto-generated method stub
              
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            myThread = new MyThread(holder);//创建一个绘图线程
            myThread.isRun = true;
            myThread.start();
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            myThread.isRun = false;
            myThread=null;
        }
        
    }
    //线程内部类
    class MyThread extends Thread
    {
        private SurfaceHolder holder;
        public boolean isRun ;
        public  MyThread(SurfaceHolder holder)
        {
            this.holder =holder; 
            isRun = true;
        }
        @Override
        public void run()
        {
            int count = 0;
            while(isRun)
            {
                Canvas c = null;
                try
                {
                    synchronized (holder)
                    {
                        c = holder.lockCanvas();//锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。
                        c.drawColor(Color.RED);//设置画布背景颜色
                        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);
                        Thread.sleep(1000);//睡眠时间为1秒
                    }
                }
                catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }
                finally
                {
                    
                    if(c!= null)
                    {
                        holder.unlockCanvasAndPost(c);//结束锁定画图,并提交改变。

                    }
                }
            }
        }
    }
}

参考资料


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:119168次
    • 积分:2770
    • 等级:
    • 排名:第13021名
    • 原创:159篇
    • 转载:3篇
    • 译文:0篇
    • 评论:45条
    博客专栏
    最新评论