WMS:SurfaceView绘制显示
- 1、SurfaceView控件使用
- 1.1 Choreographer接受VSync信号
- 1.2 自定义SurfaceView
- 1.3 结果
 
- 2、SurfaceView获取画布并显示
- 2.1 SurfaceHolder.lockCanvas()
- 2.2 SurfaceHolder.unlockCanvasAndPost(Canvas canvas)
 
1、SurfaceView控件使用
1.1 Choreographer接受VSync信号
Choreographer是Android提供的一个获取VSync信号的通道。这里
SurfaceView控件是主动上屏绘制,而一般应用如
WMS中Choreographer 配合 VSYNC 中断信号 中添加界面时从 ViewRootImpl 的 scheduleTraversals 方法开始,其内部通过 Choreographer 的 postCallback 将绘制任务添加到 Chorographer。
Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
            @Override
            public void doFrame(long frameTimeNanos) {//当vsync信号来时会调用到这里
                mHandler.sendEmptyMessage(MyHandler.TAG_UPDATE_TEXT);
                Choreographer.getInstance().removeFrameCallback(this);
                Choreographer.getInstance().postFrameCallback(this);
            }
        });
1.2 自定义SurfaceView
MySurfaceView构造函数中获取mSurfaceHolder = this.getHolder(),并设置SurfaceHolder.Callback- 继承
Runnable,Thread中运行,并Global.syncCondition.await();在这里等待vsync到来的通知消息- 线程并发处理
Lock和Condition:public class Global { public static ReentrantLock lock = new ReentrantLock(); public static Condition syncCondition = lock.newCondition(); private Global() { } }
Choreographer#doFrame中Global.syncCondition.signal();通知另一条线程更新画面
com/xhbruce/ui/MySurfaceView.java
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
    private static String TAG = "MySurfaceView";
    private SurfaceHolder mSurfaceHolder;
    private int autoNum = 0;
    private Paint mPaint = new Paint();
    public MySurfaceView(Context context) {
        this(context, null);
    }
    public MySurfaceView(Context context, AttributeSet attrs) {
        this(context, attrs , 0);
    }
    public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mSurfaceHolder = this.getHolder();
        mSurfaceHolder.addCallback(this);
        Log.d(TAG, "MySurfaceView(3) holder=" + mSurfaceHolder.toString());
    }
    public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        mSurfaceHolder = this.getHolder();
        mSurfaceHolder.addCallback(this);
        Log.d(TAG, "MySurfaceView(4) holder=" + mSurfaceHolder.toString());
    }
    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        Log.d(TAG, "surfaceCreated() holder=" + holder.toString());
        new Thread(this).start();
//        draw();//画蓝色或绿色
    }
    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
    }
    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
    }
    @Override
    public void run() {
        while (true) {
            Log.d(TAG, "run() autoNum=" + autoNum);
            Global.lock.lock();
            try {
                Global.syncCondition.await();//在这里等待vsync到来的通知消息
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                Global.lock.unlock();
            }
            draw();//画蓝色或绿色
        }
    }
    private void draw() {
        Canvas mCanvas = null;
        try {
            mCanvas = mSurfaceHolder.lockCanvas();
            if (autoNum % 2 == 0) {
                mPaint.setColor(Color.BLUE);//如果为双数则画面画成蓝色
            } else {
                mPaint.setColor(Color.GREEN);//如果为单数则画面画成绿色
            }
            mCanvas.drawRect(0, 0, getRight(), getBottom(), mPaint);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (mCanvas != null) {
                mSurfaceHolder.unlockCanvasAndPost(mCanvas);
            }
        }
        Log.d(TAG, "draw() autoNum=" + autoNum);
        autoNum++;//数字加1
    }
}
对应Activity和xml布局文件:
 com/xhbruce/surfaceviewtest/MySurfaceViewTest.java
public class MySurfaceViewTest extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_surface_view_test);
        Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
            @Override
            public void doFrame(long frameTimeNanos) {//当vsync信号来时会调用到这里
                Global.lock.lock();
                try {
                    Global.syncCondition.signal();//通知另一条线程更新画面
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    Global.lock.unlock();
                }
                Choreographer.getInstance().removeFrameCallback(this);
                Choreographer.getInstance().postFrameCallback(this);
            }
        });
    }
}
layout/activity_my_surface_view_test.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MySurfaceViewTest">
    <com.xhbruce.ui.MySurfaceView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>
1.3 结果
SurfaceView Demo
2、SurfaceView获取画布并显示
- SurfaceHolder.lockCanvas()获得Canvas对象并锁定画布
- SurfaceHolder.unlockCanvasAndPost(Canvas canvas)结束锁定画图,并提交改变,将图形显示。
2.1 SurfaceHolder.lockCanvas()
Surface的lock方法最终调用到
GraphicBufferProducer的dequeueBuffer函数获取一个Slot,如果Slot没有分配GraphicBuffer会在这时给它分配GraphicBuffer, 然后会返回一个带有BUFFER_NEEDS_REALLOCATION标记的flag, 应用侧看到这个flag后会通过requestBuffer和importBuffer接口把GraphicBuffer映射到自已的进程空间。

2.2 SurfaceHolder.unlockCanvasAndPost(Canvas canvas)
SurfaceView在更新视图时用到了两张Canvas,一张
frontCanvas和一张backCanvas,每次实际显示的是frontCanvas,backCanvas存储的是上一次更改前的视图,当使用lockCanvas()获取画布时,得到的实际上是backCanvas而不是正在显示的frontCanvas,之后你在获取到的backCanvas上绘制新视图,再unlockCanvasAndPost(Canvas canvas)此视图,那么上传的这张canvas将替换原来的frontCanvas作为新的frontCanvas,原来的frontCanvas将切换到后台作为backCanvas。



















