The relationship between Surface, SurfaceView, SurfaceHolder and SurfaceHolder.Callback

Reprinted from: http://blog.csdn.net/pathuang68/article/details/7351317

One, Surface

Surface means "surface". In the SDK documentation, the description of Surface is as follows: "Handle onto a raw buffer that is being managed by the screen compositor", translated into Chinese is "the native buffer managed by the screen compositor" "Handle to the device", this sentence includes the following two meanings:

1. Through Surface (because Surface is a handle), you can get the native buffer and its contents. Just like in C language, you can get the contents of a file through a file handle;

2. The rawbuffer is used to save the pixel data of the current window.

By extension, you can think of the Surface in Android as a place for drawing graphics or images. According to the general knowledge of Java, we know that drawing is usually done on a Canvas object. From this, we can infer that a Surface object should contain a Canvas object. In fact, this is true, and this can be easily run through debug The way of the program is proved (hold the cursor on the object variable surface, a dialog box will pop up, the content of the red box, there is a CompatileCanvas member variable in the surface surface) Of course, looking at the source code can also prove this:

 

Therefore, on the basis of the two meanings mentioned earlier, one can be added:

3. There is a Canvas member in Surface, dedicated to drawing pictures.

Therefore, the Canvas member in Surface is dedicated to a place for programmers to draw pictures, just like a blackboard; the native buffer is used to store data; Surface itself functions like a handle, and you get this handle. Canvas, native buffers and other content can be obtained.

二、SurfaceView

SurfaceView, as the name implies, is the View of Surface. You can see part or all of the contents of Surface through SurfaceView. Below, use a diagram to vividly describe the relationship between Surface and SurfaceView:

 

In other words, Surface can only display its content through SurfaceView. In this sense, the exact meaning of View in SurfaceView should be the meaning of viewport, that is, "viewport". Friends who have done database design know that assuming a data table has 20 fields, we often only use one of them. 5 fields, then you can use the SQL statement CREATEVIEW to create a view containing only those 5 fields on the basis of the original data table.

On the other hand, SurfaceView is a subclass of View in Android. In fact, all classes used for interface display in Android are subclasses of View, including those invisible and various Layouts.

So, the View in SurfaceView has two meanings:

1. The meaning of viewport

2. SurfaceView is a derived class of View

In Android, Surface is derived from Object and implements the Parcelable interface. Seeing Parcelable makes people naturally think of data containers, and SurfaceView is used to display the data in Surface. At this level, Surface is the place to manage data, and SurfaceView is the place to display data.

三、SurfaceHolder

SurfaceHolder is an interface that acts like a listener on Surface. Provides access and control of the Surface-related methods behind the SurfaceView (providing access and control over this SurfaceView's underlying surface), which allows us to perceive the creation, destruction or change of the Surface through three callback methods. There is a method getHolder in SurfaceView, which can easily get the SurfaceHolder corresponding to the Surface corresponding to the SurfaceView (a bit confusing).

 

In addition to the SurfaceHolder.Callback mentioned below, SurfaceHolder also provides many important methods, the most important of which is:

public void addCallback(Callback callback)

Add a SurfaceHolder.Callback callback interface for SurfaceHolder.

public Canvas lockCanvas();

Get a Canvas object and lock it. The Canvas object obtained is actually a member of Surface.

public Canvas lockCanvas(Rect dirty);

Same as above. But only the rectangular area specified by dirty is locked, so the efficiency is higher.

public void unlockCanvasAndPost(Canvas canvas);

After modifying the data in the Surface, release the synchronization lock, submit the changes, and then display the new data, and the relevant data in the Surface will be lost.

public void setType(int type);

Set the type of Surface and receive the following parameters:

SURFACE_TYPE_NORMAL: Normal Surface that uses RAM to cache native data

SURFACE_TYPE_HARDWARE: Suitable for DMA (Direct memory access) engine and hardware accelerated Surface

SURFACE_TYPE_GPU: Surface suitable for GPU acceleration

SURFACE_TYPE_PUSH_BUFFERS: Indicates that the Surface does not contain native data. The data used by the Surface is provided by other objects. This type of Surface is used in the Camera image preview, and the Camera is responsible for providing the preview Surface data so that the image preview will be smoother. If you set this type, you cannot call lockCanvas to get the Canvas object. It should be noted that in the higher version of the Android SDK, the setType method has been depreciated.

The purpose of the synchronization lock mechanism in 2, 3, and 4 is to prevent the data in the Surface from being changed during the drawing process.

 

From the perspective of design patterns, Surface, SurfaceView and SurfaceHolder are essentially the well-known MVC, namely Model-View-Controller. Model is the meaning of model, or data model, or more simply data, which is the Surface here; View is the view, which represents the user interaction interface, which is the SurfaceView here; SurfaceHolder can obviously be understood as the MVC Controller. It seems that the relationship between the three is much clearer.

四、SurfaceHolder.Callback

As mentioned earlier, SurfaceHolder is an interface, which allows us to perceive the creation, destruction or change of Surface by returning to the method. In fact, this is achieved through its internal static sub-interface SurfaceHolder.Callback. Three interface methods are defined in SurfaceHolder.Callback:

abstract void surfaceChanged(SurfaceHolder holder, int format, int width, int height)

When there is any structural change (format or size) of the surface, this method will be called immediately.

abstract void surfaceCreated(SurfaceHolder holder)

When the surface object is created, this method will be called immediately.

abstract void surfaceDestroyed(SurfaceHolder holder)

When the surface object is about to be destroyed, this method will be called immediately.

 

In the Android SDK documentation, in the description of SurfaceView, there is a paragraph like this:

One of the purposes of this class is to provide a surface in which a secondarythread can render into the screen. If you are going to use it this way, youneed to be aware of some threading semantics:

All SurfaceView and SurfaceHolder.Callbackmethods will be called from the thread running the SurfaceView's window(typically the main thread of the application). They thus need to correctly synchronize with any state that is also touched by the drawing thread.

You must ensure that the drawingthread only touches the underlying Surface while it is valid -- between SurfaceHolder.Callback.surfaceCreated() and SurfaceHolder.Callback.surfaceDestroyed().

This passage is very important, and the general meaning is as follows:

One of the purposes of this class is to provide a surface that can use another thread (the second thread) for screen rendering (Annotation: UI thread and drawing thread can be separated). If you plan to use this way, you should pay attention to some thread semantics:

All the methods declared in SurfaceView and SurfaceHolder.Callback must be called in the thread running the SurfaceView window (typically, the main thread of the application. Annotation: UI thread), because they need to be correctly accessed by the drawing thread at the same time Various states are synchronized.

It must be ensured that only when the underlying Surface is valid-between the two method calls SurfaceHolder.Callback.surfaceCreated() and SurfaceHolder.Callback.surfaceDestroyed(), access it.

 

Below, let’s get a feel for it through a very simple example (the code is taken from http://www.cnblogs.com/xuling/archive/2011/06/06/android.html with some structural changes), please Pay attention to the comments in the code:

1. Create an Android Project project in Android Studio and choose to generate the default MainActivity.java

2. Create a drawing thread as follows:

package com.gao.android.surface_holder;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.SurfaceHolder;

// 绘制线程
public class MyThread extends Thread {
    private SurfaceHolder holder;
    private boolean run;

    public MyThread(SurfaceHolder holder) {
        this.holder = holder;
        run = true;
    }

    @Override
    public void run() {
        int counter = 0;
        Canvas canvas = null;
        while(run) {
            // 具体绘制工作
            try {
                // 获取Canvas对象,并锁定之
                canvas= holder.lockCanvas();

                // 设定Canvas对象的背景颜色
                canvas.drawColor(Color.WHITE);

                // 创建画笔
                Paint p = new Paint();
                // 设置画笔颜色
                p.setColor(Color.BLACK);
                // 设置文字大小
                p.setTextSize(30);

                // 创建一个Rect对象rect
                Rect rect = new Rect(100, 50, 380, 330);
                // 在canvas上绘制rect
                canvas.drawRect(rect,p);
                // 在canvas上显示时间
                canvas.drawText("Interval = " + (counter++) + " seconds.", 100, 410, p);
                Thread.sleep(1000);
            }
            catch(Exception e) {
                e.printStackTrace();
            }
            finally {
                if(canvas != null) {
                    // 解除锁定,并提交修改内容
                    holder.unlockCanvasAndPost(canvas);
                }
            }
        }
    }

    public boolean isRun() {
        return run;
    }

    public void setRun(boolean run) {
        this.run = run;
    }
}

3. Customize a SurfaceView class as follows:

package com.gao.android.surface_holder;

import android.content.Context;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {

    private SurfaceHolder holder;
    private MyThread myThread;

    public MySurfaceView(Context context) {
        super(context);

        // 通过SurfaceView获得SurfaceHolder对象
        holder = getHolder();

        // 为holder添加回调结构SurfaceHolder.Callback
        holder.addCallback(this);

        // 创建一个绘制线程,将holder对象作为参数传入,这样在绘制线程中就可以获得holder
        // 对象,进而在绘制线程中可以通过holder对象获得Canvas对象,并在Canvas上进行绘制
        myThread = new MyThread(holder);
    }

    // 实现SurfaceHolder.Callback接口中的三个方法,都是在主线程中调用,而不是在绘制线程中调用的
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // 启动线程。当这个方法调用时,说明Surface已经有效了
        myThread.setRun(true);
        myThread.start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // 结束线程。当这个方法调用时,说明Surface即将要被销毁了
        myThread.setRun(false);
    }
}

4. Modify the MainActivity.java code to be as follows:

package com.gao.android.surface_holder;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(new MySurfaceView(this));
    }
}

 operation result:

Obviously, we can do many more interesting things in the run method of MyThread. To figure out the concepts of Surface, SurfaceView, SurfaceHolder and SurfaceHolder.Callback, as well as the relationship between them, should be of considerable help for us to use them better.

Guess you like

Origin blog.csdn.net/qq_37381177/article/details/111635096