preface

From Android

Android provides a View for drawing processing, View can meet most of the needs of drawing, but sometimes it can be more than enough. As we know, the View redraws the View by refreshing, and the Android system redraws the screen by issuing the VSYNC signal at an interval of 16ms. If the View does everything you need to do in 16ms, the user won’t feel stuck visually; Too much operation logic, especially on an interface that needs to be refreshed frequently, such as a game interface, will block the main thread and cause the screen to stall. B. To bounce over 47 frames! B. To bounce over 47 frames! The application may be doing too much work on its main thread. To avoid this problem, Android provides The SurfaceView component.

View and SurfaceView

  • The View is mostly for active updates, while the SurfaceView is mostly for passive updates, such as frequent refreshes.
  • The View refreshes the screen in the main thread, whereas the SurfaceView usually refreshes the page in a child thread.
  • The View does not use double buffering when drawing, whereas the SurfaceView already implements double buffering in the underlying implementation mechanism. In summary, if your custom View needs to be refreshed frequently, or the refresh process is a lot of data, then you should consider using SurfaceView instead of View.

The use of SurfaceView

Although the use of SurfaceView is more complex than View, but SurfaceView in the use of a set of template code, most of the SurfaceView drawing operations can be written using such template code. So the SurfaceView is much easier to use.

Create a template for SurfaceView
1. Create SurfaceView

Create a custom MySurfaceView that inherits from the SurfaceView and implements two interfaces — surfaceHolder.callback, Runnable, and the interface methods as follows:

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    }

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

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    }

    @Override
    public void run() {
    }
}Copy the code
Initialize the SurfaceView

In the constructor of a custom SurfaceView, you need to initialize the SurfaceView. Usually you need to define the following three member variables, as follows:

private SurfaceHolder mHolder; // Canvas private canvas mCanvas; Private Boolean mIsDrawing;Copy the code

The initialization method is to initialize a SurfaceHolder object and register the SurfaceHolder callback as follows:

mHolder = getHolder();
mHolder.addCallback(this);Copy the code

The other two member variables are Canvas and flag bit. Use Canvas for drawing; Use flag bits to control the child threads mentioned earlier for drawing.

3. Use SurfaceView

The current Canvas drawing object is obtained by using the lockCanvas() method of the SurfaceHolder object. Now you can draw just like you did in the View. Note here that the acquired Canvas is still a continuation of the previous Canvas, rather than a new Canvas. Therefore, previous drawing operations are retained. If you need to erase, you can clear the screen by using the drawColor() method before drawing.

The surfaceCreated() method opens the child thread for drawing using a while (mIsDrawing) {} loop, which uses the SurfaceView’s three callback methods. The Canvas object is obtained by the lockCanvas() method to draw, and the Canvas content is submitted by the unlockCanvasAndPost(mCanvas) method. The entire SurfaceView template code looks like this:

import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.SurfaceHolder; import android.view.SurfaceView; /** * Created by Deeson on 2017/5/23. */ public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable { private SurfaceHolder mHolder; // Canvas private canvas mCanvas; Private Boolean mIsDrawing; public MySurfaceView (Context context) { super(context); init(); } public MySurfaceView (Context context, AttributeSet attrs) { super(context, attrs); init(); } public MySurfaceView (Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mHolder = getHolder(); mHolder.addCallback(this); setFocusable(true); setFocusableInTouchMode(true); this.setKeepScreenOn(true); } @Override public void surfaceCreated(SurfaceHolder holder) { mIsDrawing = true; new Thread(this).start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { mIsDrawing = false; } @Override public void run() { while (mIsDrawing) { draw(); } } private void draw() { try { mCanvas = mHolder.lockCanvas(); //draw something } catch (Exception e) { e.printStackTrace(); } finally { if (null ! = mCanvas) { mHolder.unlockCanvasAndPost(mCanvas); }}}}Copy the code

Basic can meet most of the code above SurfaceView drawing requirements, only need to pay attention to that in the drawing method, will mHolder. UnlockCanvasAndPost (mCanvas); Method ina finally block of code to ensure that the content is committed each time.

The last

For an example walkthrough of SurfaceView, check out my articleAndroid: Bezier curve principle analysis

By convention, a demo download is required, as shown in the GIF below:





mySurfaceView.gif