可以在子线程绘画的View SurfaceView

转载请注明出处:王亟亟的大牛之路

最近两天都没有写文章,一方面是自己在看书,一方面不知道写什么,本来昨天想写Glide或者RxAndroid的东西结果公司的“狗屎”网怎么都刷不好Gradle我也是无语了(也没用),准备今天背着笔记本 回家搞,真是服了。。


抱怨的话不说了,来看下这一篇要讲的主角 SurfaceView,关于SurfaceView的文章其实在别的一些站点上也有,因为我之前没写过,所以也就一直没整这部分的内容(别人写的好坏反正找好的点自己吸收吧,嘿嘿)

问题:SurfaceView是什么?

View类的子类

public class SurfaceView extends View

surfaceView是在一个新起的单独线程中可以重新绘制画面而View必须在UI的主线程中更新画面。

这点很重要,那我们可以在哪使用它?那些一直在刷的,还会耗性能的一些UI内容我们可以让他去画,毕竟不在主线程(想想渐变这类的东西)

再例举一些使用场景,假设我要画一个视图他和用户有交互,那么用View还是SurfaceView?

像这样的情况就比较推荐用View因为要有Touch事件,用View更合适。而0交互的那些场景用用SurfaceView对性能会有一定的帮助,接下来用例子来具体描述如何用SurfaceView。


先上效果图

可以在子线程绘画的View SurfaceView_第1张图片

效果很简单就是在一个Activity里设置了个白色背景,然后写了个“你好”。

来看下代码(一些知识点在标注里说明)

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;

/**
 * Created by jiajiewang on 16/3/22.
 */

public class CustomView extends SurfaceView implements SurfaceHolder.Callback, View.OnTouchListener {
    private Context context;
    private SurfaceHolder surfaceHolder;
    private CustomThread customThread;


    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setKeepScreenOn(true);
        this.setFocusable(true);
        //用于触摸事件
        this.setLongClickable(true);
        this.context = context;
        //获取对象实例
        surfaceHolder = this.getHolder();
        // 给SurfaceView添加回调
        surfaceHolder.addCallback(this);
        //创建工作线程
        customThread = new CustomThread(surfaceHolder);

    }

    //创建的时候调用
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        customThread.canRun = true;
        //工作线程开始工作
        customThread.start();
        Log.d("-->surfaceCreated", "surfaceCreated");
    }

    //发生改变的时候调用
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

        Log.d("-->surfaceChanged", "surfaceChanged");
    }

    //销毁时的时候调用
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

        customThread.canRun = false;
        Log.d("-->surfaceDestroyed", "surfaceDestroyed");

    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:


                Log.d("MotionEvent", "ACTION_DOWN");

                break;

            case MotionEvent.ACTION_UP:


                Log.d("MotionEvent", "ACTION_UP");

                break;


            case MotionEvent.ACTION_MOVE:


                Log.d("MotionEvent", "ACTION_MOVE");

                break;


        }

        return super.onTouchEvent(event);

    }
}

//工作线程
class CustomThread extends Thread {
    private SurfaceHolder surfaceHolder;
    public boolean canRun;

    public CustomThread(SurfaceHolder surfaceHolder) {
        this.surfaceHolder = surfaceHolder;
        canRun = true;
    }

    @Override
    public void run() {

        while (canRun) {
            Canvas canvas = null;
            //线程同步
            synchronized (surfaceHolder) {
                //创建画笔
                Paint paint = new Paint();
                paint.setColor(Color.GREEN);
                paint.setTextSize(200);
                // 锁定画布(想一下,类似Bitmap的效果)
                canvas = surfaceHolder.lockCanvas();
                //画背景
                canvas.drawColor(Color.WHITE);
                //画字
                canvas.drawText("妈蛋", 100, 300, paint);
            }

            if (canvas != null) {
                // 结束锁定
                surfaceHolder.unlockCanvasAndPost(canvas);
            }

        }

    }

流程:

这是一个自定义的SurfaceView并实现了SurfaceHolder.Callback

在这个自定义SurfaceView被创建的时候去开启工作线程去做了该做的事,MainActivity没做任何事也就是 加载一下,还是在XML里引入的。

  .wjj.surfaceviewdemo.CustomView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content" />

那我们来看下 SurfaceView一些比较重要的(常用的)方法。

getHolder() 获取SurfaceHolder对象,Surface 就在SurfaceHolder对象内

Canvas lockCanvas()或则Canvas lockCanvas(Rect dirty) 获取Canvas对象

unlockCanvasAndPost(Canvas canvas) 函数会释放该锁,用于操作UI

在调用lockCanvas函数获取Canvas后,SurfaceView会获取Surface的一个同步锁直到调用unlockCanvasAndPost(Canvas canvas)函数才释放该锁,这里的同步机制保证在Surface绘制过程中不会被改变(被摧毁、修改)。

再说一下绘制的类型(更好的运用性能)

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对象了。 

因为没有什么其他第三方资源所以就不存源码了。

如果在学习的过程中有什么问题或者项目中有什么问题需要找人探讨的可以扫以下微信和我沟通(私人微信都不是什么平台的会相对回的比较快,骚扰的别来,坏人烂JJ!!)
可以在子线程绘画的View SurfaceView_第2张图片

你可能感兴趣的:(各种小案例,自定义控件开发之路)