掌握聚合最新动态了解行业最新趋势
API接口,开发服务,免费咨询服务

Android SurFaceView的用法详解

在Android开发中,SurfaceView 是一个非常强大的视图组件,特别适用于需要高性能图形渲染的应用场景,如游戏、视频播放和实时摄像头预览等。与普通的 View 相比,SurfaceView 提供了一个独立的绘图表面,可以在后台线程中进行绘制,从而避免了主线程被阻塞的问题。本文将详细介绍 SurfaceView 的用法,包括其基本概念、创建步骤、常见应用场景以及优化技巧

一、什么是SurfaceView

SurfaceView 是 View 的一个子类,它提供了一个专门用于绘制的 Surface 对象。这个 Surface 对象是双缓冲的,可以实现高效的图形渲染。SurfaceView 的主要特点如下:

  1. 独立的绘图表面:SurfaceView 拥有一个独立的绘图表面,可以在这个表面上进行复杂的图形绘制操作。

  2. 后台线程绘制:可以在后台线程中进行绘制操作,不会阻塞主线程,保证了应用的流畅性。

  3. 支持硬件加速:SurfaceView 可以利用硬件加速来提高图形渲染性能。

二、SurfaceView的基本结构

SurfaceView 的基本结构主要包括以下几个部分:

  1. SurfaceHolder:SurfaceHolder 是 SurfaceView 的一个接口,提供了对 Surface 的访问和控制方法。通过 SurfaceHolder 可以获取 Surface 对象,并设置回调函数。

  2. Surface:Surface 是实际的绘图表面,可以通过 Canvas 或 OpenGL 进行绘制。

  3. Callback:SurfaceHolder.Callback 接口定义了三个回调方法,分别在 Surface 创建、改变和销毁时调用。

三、如何使用SurfaceView

使用 SurfaceView 主要分为以下几个步骤:

  1. 创建SurfaceView

首先,在布局文件中添加一个 SurfaceView 组件,或者在代码中动态创建。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>或者在代码中动态创建:
SurfaceView surfaceView = new SurfaceView(this);
surfaceView.setLayoutParams(new ViewGroup.LayoutParams(
    ViewGroup.LayoutParams.MATCH_PARENT,
    ViewGroup.LayoutParams.MATCH_PARENT));
((ViewGroup) findViewById(android.R.id.content)).addView(surfaceView);
  1. 设置SurfaceHolder.Callback

为了在 Surface 创建、改变和销毁时得到通知,需要为 SurfaceView 设置 SurfaceHolder.Callback。

surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // Surface 创建时调用
    }
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // Surface 改变时调用
    }
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface 销毁时调用
    }
});
  1. 在后台线程中绘制

为了不阻塞主线程,通常会在一个单独的线程中进行绘制操作。可以通过 Handler 或 Thread 来实现。

private class DrawThread extends Thread {
    private SurfaceHolder mSurfaceHolder;
    private boolean mRunning = false;
    public DrawThread(SurfaceHolder surfaceHolder) {
        mSurfaceHolder = surfaceHolder;
    }
    public void setRunning(boolean running) {
        mRunning = running;
    }
    @Override
    public void run() {
        while (mRunning) {
            Canvas canvas = null;
            try {
                canvas = mSurfaceHolder.lockCanvas();
                if (canvas != null) {
                    // 在这里进行绘制操作
                    draw(canvas);
                }
            } finally {
                if (canvas != null) {
                    mSurfaceHolder.unlockCanvasAndPost(canvas);
                }
            }
        }
    }
    private void draw(Canvas canvas) {
        // 具体的绘制逻辑
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        canvas.drawCircle(100, 100, 50, paint);
    }
}
// 启动绘制线程
DrawThread drawThread = new DrawThread(surfaceView.getHolder());
drawThread.setRunning(true);
drawThread.start();
// 停止绘制线程
drawThread.setRunning(false);
drawThread.interrupt();

四、常见应用场景

SurfaceView 适用于多种需要高性能图形渲染的场景,以下是一些常见的应用场景:

  1. 游戏开发

SurfaceView 是游戏开发中的常用组件,特别是在需要频繁更新画面的游戏场景中。例如,飞行射击游戏、赛车游戏等。

  1. 视频播放

SurfaceView 可以用来显示视频流,配合 MediaPlayer 可以实现视频播放功能。例如,视频播放器、直播应用等。

  1. 实时摄像头预览

SurfaceView 可以用来显示摄像头的实时预览画面,常用于相机应用、AR/VR应用等。

  1. 图形绘制

对于需要复杂图形绘制的应用,SurfaceView 提供了高效的绘图能力。例如,绘画应用、地图应用等。

五、优化技巧

虽然 SurfaceView 提供了高效的图形渲染能力,但在实际开发中仍然需要注意一些优化技巧,以确保最佳性能。

  1. 避免频繁锁定和解锁Canvas

频繁地锁定和解锁 Canvas 会导致性能下降。尽量减少 lockCanvas 和 unlockCanvasAndPost 的调用次数。

while (mRunning) {
    Canvas canvas = null;
    try {
        canvas = mSurfaceHolder.lockCanvas();
        if (canvas != null) {
            // 在这里进行绘制操作
            draw(canvas);
        }
    } finally {
        if (canvas != null) {
            mSurfaceHolder.unlockCanvasAndPost(canvas);
        }
    }
}
  1. 使用双缓冲技术

SurfaceView 内部已经实现了双缓冲技术,但你也可以在绘制时手动实现双缓冲,以进一步提高性能。

private Bitmap mBufferBitmap;
private Canvas mBufferCanvas;
public void initBuffer(int width, int height) {
    mBufferBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    mBufferCanvas = new Canvas(mBufferBitmap);
}
public void draw(Canvas canvas) {
    // 在缓冲区上绘制
    mBufferCanvas.drawColor(Color.TRANSPARENT);
    Paint paint = new Paint();
    paint.setColor(Color.RED);
    mBufferCanvas.drawCircle(100, 100, 50, paint);
    // 将缓冲区的内容绘制到Surface上
    canvas.drawBitmap(mBufferBitmap, 0, 0, null);
}
  1. 优化绘制逻辑

尽量减少不必要的绘制操作,避免在每一帧中都重新计算所有内容。可以使用缓存机制来存储已经绘制好的内容。

private Bitmap mCachedBitmap;
private boolean mNeedsRedraw = true;
public void draw(Canvas canvas) {
    if (mNeedsRedraw) {
        mBufferCanvas.drawColor(Color.TRANSPARENT);
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        mBufferCanvas.drawCircle(100, 100, 50, paint);
        mCachedBitmap = mBufferBitmap.copy(Bitmap.Config.ARGB_8888, true);
        mNeedsRedraw = false;
    }
    canvas.drawBitmap(mCachedBitmap, 0, 0, null);
}
  1. 释放资源

在 SurfaceView 不再使用时,及时释放相关资源,避免内存泄漏。

@Override
protected void onDestroy() {
    super.onDestroy();
    drawThread.setRunning(false);
    drawThread.interrupt();
    try {
        drawThread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    mBufferBitmap.recycle();
    mBufferBitmap = null;
}

SurfaceView 是一个非常强大的视图组件,适用于需要高性能图形渲染的应用场景。通过本文的介绍,我们了解了 SurfaceView 的基本概念、创建步骤、常见应用场景以及优化技巧。希望这些内容能够帮助你在实际开发中更好地使用 SurfaceView,提升应用的性能和用户体验。无论是游戏开发、视频播放还是实时摄像头预览,SurfaceView 都是一个值得信赖的选择。

声明:所有来源为“聚合数据”的内容信息,未经本网许可,不得转载!如对内容有异议或投诉,请与我们联系。邮箱:marketing@think-land.com

  • 全球天气预报

    支持全球约2.4万个城市地区天气查询,如:天气实况、逐日天气预报、24小时历史天气等

    支持全球约2.4万个城市地区天气查询,如:天气实况、逐日天气预报、24小时历史天气等

  • 购物小票识别

    支持识别各类商场、超市及药店的购物小票,包括店名、单号、总金额、消费时间、明细商品名称、单价、数量、金额等信息,可用于商品售卖信息统计、购物中心用户积分兑换及企业内部报销等场景

    支持识别各类商场、超市及药店的购物小票,包括店名、单号、总金额、消费时间、明细商品名称、单价、数量、金额等信息,可用于商品售卖信息统计、购物中心用户积分兑换及企业内部报销等场景

  • 涉农贷款地址识别

    涉农贷款地址识别,支持对私和对公两种方式。输入地址的行政区划越完整,识别准确度越高。

    涉农贷款地址识别,支持对私和对公两种方式。输入地址的行政区划越完整,识别准确度越高。

  • 人脸四要素

    根据给定的手机号、姓名、身份证、人像图片核验是否一致

    根据给定的手机号、姓名、身份证、人像图片核验是否一致

  • 个人/企业涉诉查询

    通过企业关键词查询企业涉讼详情,如裁判文书、开庭公告、执行公告、失信公告、案件流程等等。

    通过企业关键词查询企业涉讼详情,如裁判文书、开庭公告、执行公告、失信公告、案件流程等等。

0512-88869195
数 据 驱 动 未 来
Data Drives The Future