SurfaceView的使用

本文详细介绍了SurfaceView的基本概念、使用方式及实例应用。SurfaceView作为重要的绘图容器,支持双缓冲机制,可在子线程更新UI,提高程序响应速度。文中通过具体示例展示了如何利用SurfaceView实现动态动画和视频播放器。

1.定义

SurfaceView继承自View,内嵌了一个专门用于绘制的Surface,Surfaceview不仅可以控制这个Surface的格式和尺寸,还能控制其绘制位置;因为可以直接从内存或者DMA等硬件接口取得图像数据,所以是个非常重要的绘图容器。

2.使用

首先要知道SurfaceView的一些特性,然后根据特性决定用途;

* SurfaceView 单位时间内完成界面的大量多次更新

* 双缓冲机制 :

* A线程----更新ui -----后台计算---更新ui

* B线程----后台计算----更新ui ---后台计算

* 可以在子线程更新ui

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

surfaceView.getHolder().addCallback(new Callback() {

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        //surfaceView被销毁时调用
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        //surfaceView被创建时调用
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        //surfaceView发生变化时调用
    }
});

首先继承SurfaceView并实现SurfaceHolder.Callback接口
使用接口的原因:因为使用SurfaceView 有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始(。基本上我们可以把它当作显存的一个映射,写入到Surface 的内容可以被直接复制到显存从而显示出来,这使得显示速度会非常快),而在Surface 被销毁之前必须结束。所以Callback 中的surfaceCreated 和surfaceDestroyed 就成了绘图处理代码的边界。

3.实例

sv.getHolder().addCallback(new Callback() {

                @Override
                public void surfaceDestroyed(SurfaceHolder holder) {
                    System.out.println("surface被销毁了");
                    flag = false;
                }

                @Override
                public void surfaceCreated(SurfaceHolder holder) {
                    System.out.println("surface创建了");
                    flag = true;
                    new Thread(){
                        public void run() {
                            for(int i = 0;i<100;i++){
                                if(!flag){
                                    return ;
                                }
                            //界面里面内容显示的控制器
                                SurfaceHolder holder = sv.getHolder();
                                Canvas  canvas = holder.lockCanvas();
                                canvas.drawColor(Color.BLACK);
                                int radius = 5+i;
                                Paint paint = new Paint();
                                paint.setColor(Color.RED);
                                canvas.drawCircle(250, 250, radius, paint);
                                holder.unlockCanvasAndPost(canvas);
                                SystemClock.sleep(100);
                            }
                        };
                    }.start();
                }

                @Override
                public void surfaceChanged(SurfaceHolder holder, int format, int width,
                        int height) {
                    System.out.println("surface大小发生了变化");
                }
            });

   上述代码实现的内容是canvas动态地画一个半径逐渐增大的圆形成的动画;

   整个过程:继承SurfaceView并实现SurfaceHolder.Callback接口 ----> SurfaceView.getHolder()获得SurfaceHolder对象 ---->SurfaceHolder.addCallback(callback)添加回调函数----   >SurfaceHolder.lockCanvas()获得Canvas对象并锁定画布----> Canvas绘画 ---->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)结束锁定画图,并提交改变,将图形显示。

 

   下面贴出SurfaceView实现视频播放器的实例:

    

            sv = (SurfaceView) findViewById(R.id.sv);
            sp = getSharedPreferences("config", MODE_PRIVATE);

            sv.getHolder().addCallback(new Callback() {

                @Override
                public void surfaceDestroyed(SurfaceHolder holder) {
                    System.out.println("surface被销毁");
                    if(mediaPlayer!=null){
                        int position = mediaPlayer.getCurrentPosition();
                        Editor editor  = sp.edit();
                        editor.putInt("position", position);
                        editor.commit();
                        mediaPlayer.stop();
                        mediaPlayer.release();
                    }
                }

                @Override
                public void surfaceCreated(SurfaceHolder holder) {
                    System.out.println("surface被创建");
                    try {
                        mediaPlayer = new MediaPlayer();
                        mediaPlayer.setDataSource("/mnt/sdcard/oppo.3gp");
                        mediaPlayer.prepare();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    //指定多媒体的内容实在holder里面显示
                    mediaPlayer.setDisplay(holder);
                    mediaPlayer.start();
                    mediaPlayer.seekTo(sp.getInt("position", 0));
                }

                @Override
                public void surfaceChanged(SurfaceHolder holder, int format, int width,
                        int height) {
                }
            });

4.小结

   SurfaceView的使用远不止于此,它比想象的更加强大,后面会涉及到SurfaceView的进阶使用.

### 使用 Android SurfaceView 的示例详解 #### 创建自定义 `SurfaceView` 类 为了更好地控制绘图操作,通常会创建一个继承于 `SurfaceView` 并实现 `SurfaceHolder.Callback` 接口的类。这允许监听表面状态的变化并执行相应的动作。 ```java public class MyDrawingView extends SurfaceView implements SurfaceHolder.Callback { private DrawThread drawThread; public MyDrawingView(Context context, AttributeSet attrs) { super(context, attrs); getHolder().addCallback(this); // 添加回调接口 setFocusable(true); // 设置焦点可获取 setFocusableInTouchMode(true); // 屏幕触摸模式下也可获得焦点 this.drawThread = new DrawThread(getHolder(), this); } @Override public void surfaceCreated(SurfaceHolder holder) { drawThread.setRunning(true); drawThread.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} @Override public void surfaceDestroyed(SurfaceHolder holder) { boolean retry = true; while (retry) { try { drawThread.join(); // 等待线程结束 retry = false; } catch (InterruptedException e) {} } } } ``` 此代码片段展示了如何设置基本结构来处理生命周期事件以及启动/停止后台绘画线程[^1]。 #### 实现绘制逻辑 接下来,在单独的工作线程中完成实际的画面渲染工作: ```java class DrawThread extends Thread { private final SurfaceHolder _surfaceHolder; private final MyDrawingView _panel; private volatile boolean _running = false; public DrawThread(SurfaceHolder surfaceHolder, MyDrawingView panel) { _surfaceHolder = surfaceHolder; _panel = panel; } public void setRunning(boolean run) { _running = run; } @Override public void run() { Canvas c; while (_running) { c = null; try { c = _surfaceHolder.lockCanvas(null); synchronized (_surfaceHolder) { doDraw(c); } } finally { if (c != null) { _surfaceHolder.unlockCanvasAndPost(c); } } } } private void doDraw(Canvas canvas) { // 绘制具体的内容到画布上... Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.RED); canvas.drawRect(0, 0, getWidth(), getHeight(), paint); } } ``` 这里实现了持续更新画面的功能,并通过同步机制确保多线程环境下的安全性。 #### 将视图添加至布局文件 最后一步是在 XML 布局资源文件里声明这个新的组件实例: ```xml <com.example.MyDrawingView android:id="@+id/my_drawing_view" android:layout_width="match_parent" android:layout_height="wrap_content"/> ``` 这样就可以在应用程序界面中显示由 `MyDrawingView` 控件负责管理的图形区域了。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值