La relación entre Surface, SurfaceView, SurfaceHolder y SurfaceHolder.

Reimpreso de: http://blog.csdn.net/pathuang68/article/details/7351317

Uno, superficie

Superficie significa "superficie". En la documentación del SDK, la descripción de Surface es la siguiente: "Manejar en un búfer sin formato que está siendo administrado por el compositor de pantalla", traducido al chino es "el búfer nativo administrado por el compositor de pantalla" "Manejar en el dispositivo", esta oración incluye los siguientes dos significados:

1. A través de Surface (porque Surface es un identificador), puede obtener el búfer nativo y su contenido. Al igual que en el lenguaje C, puede obtener el contenido de un archivo a través de un identificador de archivo;

2. El búfer sin formato se utiliza para guardar los datos de píxeles de la ventana actual.

Por extensión, puede pensar en Surface en Android como un lugar para dibujar gráficos o imágenes. De acuerdo con el conocimiento general de Java, sabemos que el dibujo se realiza generalmente en un objeto Canvas. De esto, podemos inferir que un objeto Surface debe contener un objeto Canvas. De hecho, esto es cierto, y esto se puede ejecutar fácilmente a través de debug Se prueba la forma del programa (mantenga el cursor en la superficie de la variable del objeto, aparecerá un cuadro de diálogo, el contenido del cuadro rojo, hay una variable de miembro CompatileCanvas en la superficie de la superficie) Por supuesto, mirando la fuente El código también puede probar esto:

 

Por tanto, en base a los dos significados mencionados anteriormente, se puede agregar uno más:

3. Hay un miembro de Canvas en Surface, dedicado a dibujar imágenes.

Por lo tanto, el miembro Canvas en Surface está dedicado a un lugar para que los programadores dibujen imágenes, como una pizarra; el búfer nativo se usa para almacenar datos; Surface en sí funciona como un identificador, y usted obtiene este identificador. Canvas, búferes nativos y se puede obtener otro contenido.

二 、 SurfaceView

SurfaceView, como su nombre lo indica, es la Vista de Surface. Puede ver parte o todo el contenido de Surface a través de SurfaceView. A continuación, use un diagrama para describir vívidamente la relación entre Surface y SurfaceView:

 

En otras palabras, Surface solo puede mostrar su contenido a través de SurfaceView. En este sentido, el significado exacto de View en SurfaceView debería ser el significado de viewport, es decir, "viewport". Los amigos que han realizado el diseño de bases de datos saben que asumiendo que una tabla de datos tiene 20 campos, a menudo solo usamos uno de ellos. campos, luego puede usar la instrucción SQL CREATEVIEW para crear una vista que contenga solo esos 5 campos sobre la base de la tabla de datos original.

Por otro lado, SurfaceView es una subclase de View en Android. De hecho, todas las clases utilizadas para la visualización de la interfaz en Android son subclases de Vista, incluidas las invisibles y varios diseños.

Entonces, la Vista en SurfaceView tiene dos significados:

1. El significado de la ventana gráfica

2. SurfaceView es una clase de vista derivada

En Android, Surface se deriva de Object e implementa la interfaz Parcelable. Ver Parcelable hace que la gente piense naturalmente en contenedores de datos, y SurfaceView se usa para mostrar los datos en Surface. En este nivel, Surface es el lugar para administrar datos y SurfaceView es el lugar para mostrar datos.

三 、 SurfaceHolder

SurfaceHolder es una interfaz que actúa como un oyente en Surface. Proporciona acceso y control de los métodos relacionados con Surface detrás de SurfaceView (proporcionando acceso y control sobre la superficie subyacente de SurfaceView), lo que nos permite percibir la creación, destrucción o cambio de Surface a través de tres métodos de devolución de llamada. Hay un método getHolder en SurfaceView, que puede obtener fácilmente el SurfaceHolder correspondiente a la Surface correspondiente a SurfaceView (un poco confuso).

 

Además del SurfaceHolder.Callback mencionado a continuación, SurfaceHolder también proporciona muchos métodos importantes, el más importante de los cuales es:

public void addCallback(Callback callback)

Agregue una interfaz de devolución de llamada SurfaceHolder.Callback para SurfaceHolder.

public Canvas lockCanvas();

Consigue un objeto Canvas y ciérralo. El objeto Canvas obtenido es en realidad un miembro de Surface.

public Canvas lockCanvas(Rect dirty);

Lo mismo que arriba. Pero solo el área rectangular especificada por sucio está bloqueada, por lo que la eficiencia es mayor.

public void unlockCanvasAndPost(Canvas canvas);

Después de modificar los datos en Surface, libere el bloqueo de sincronización, envíe los cambios y luego muestre los nuevos datos, y los datos relevantes en Surface se perderán.

public void setType(int type);

Establezca el tipo de superficie y reciba los siguientes parámetros:

SURFACE_TYPE_NORMAL: Superficie normal que usa RAM para almacenar en caché datos nativos

SURFACE_TYPE_HARDWARE: Adecuado para motor DMA (acceso directo a memoria) y Surface acelerada por hardware

SURFACE_TYPE_GPU: superficie adecuada para aceleración de GPU

SURFACE_TYPE_PUSH_BUFFERS: indica que la superficie no contiene datos nativos. Los datos utilizados por la superficie son proporcionados por otros objetos. Este tipo de superficie se utiliza en la vista previa de la imagen de la cámara, y la cámara es responsable de proporcionar los datos de la superficie de vista previa para que el la vista previa de la imagen será más fluida. Si establece este tipo, no puede llamar a lockCanvas para obtener el objeto Canvas. Cabe señalar que en la versión superior del SDK de Android, el método setType se ha depreciado.

El propósito del mecanismo de bloqueo de sincronización en 2, 3 y 4 es evitar que los datos en la superficie cambien durante el proceso de dibujo.

 

Desde la perspectiva de los patrones de diseño, Surface, SurfaceView y SurfaceHolder son esencialmente los MVC más conocidos, a saber, Model-View-Controller. Modelo es el significado de modelo, o modelo de datos, o más simplemente datos, que es la superficie aquí; Vista es la vista, que representa la interfaz de interacción del usuario, que es SurfaceView aquí; SurfaceHolder obviamente puede entenderse como el controlador MVC. Parece que la relación entre los tres es mucho más clara.

四 、 SurfaceHolder.Callback

Como se mencionó anteriormente, SurfaceHolder es una interfaz, que nos permite percibir la creación, destrucción o cambio de Surface volviendo al método. De hecho, esto se logra a través de su subinterfaz estática interna SurfaceHolder.Callback. Se definen tres métodos de interfaz en SurfaceHolder.Callback:

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

Cuando haya algún cambio estructural (formato o tamaño) de la superficie, este método se llamará de inmediato.

abstract void surfaceCreated(SurfaceHolder holder)

Cuando se crea el objeto de superficie, este método se llamará inmediatamente.

abstract void surfaceDestroyed(SurfaceHolder holder)

Cuando el objeto de superficie esté a punto de ser destruido, este método se llamará inmediatamente.

 

En la documentación del SDK de Android, en la descripción de SurfaceView, hay un párrafo como este:

Uno de los propósitos de esta clase es proporcionar una superficie en la que un subproceso secundario pueda representar en la pantalla. Si lo va a usar de esta manera, debe tener en cuenta algunas semánticas de subprocesos:

Todos los métodos SurfaceView y SurfaceHolder.Callback se llamarán desde el hilo que ejecuta la ventana de SurfaceView (normalmente el hilo principal de la aplicación). Por lo tanto, necesitan sincronizarse correctamente con cualquier estado que también sea tocado por el hilo de dibujo.

Debe asegurarse de que el hilo de dibujo solo toque la superficie subyacente mientras sea válida, entre SurfaceHolder.Callback.surfaceCreated () y SurfaceHolder.Callback.surfaceDestroyed ().

Este pasaje es muy importante y el significado general es el siguiente:

Uno de los propósitos de esta clase es proporcionar una superficie que pueda usar otro hilo (el segundo hilo) para la representación de pantalla (Anotación: el hilo de la interfaz de usuario y el hilo de dibujo se pueden separar). Si planea usar de esta manera, debe prestar atención a algunas semánticas de subprocesos:

Todos los métodos declarados en SurfaceView y SurfaceHolder.Callback deben llamarse en el subproceso que ejecuta la ventana SurfaceView (normalmente, el subproceso principal de la aplicación. Anotación: subproceso de interfaz de usuario), porque el subproceso de dibujo debe acceder correctamente a ellos al mismo tiempo. tiempo Se sincronizan varios estados.

Debe asegurarse de que solo cuando la superficie subyacente sea válida, entre las dos llamadas de método SurfaceHolder.Callback.surfaceCreated () y SurfaceHolder.Callback.surfaceDestroyed (), acceda a ella.

 

A continuación, veamos cómo funciona a través de un ejemplo muy simple (el código se tomó de http://www.cnblogs.com/xuling/archive/2011/06/06/android.html con algunos cambios estructurales), pague atención a los comentarios en el código:

1. Cree un proyecto de proyecto de Android en Android Studio y elija generar el MainActivity.java predeterminado

2. Cree un hilo de dibujo de la siguiente manera:

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. Personalice una clase SurfaceView de la siguiente manera:

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. Modifique el código MainActivity.java para que sea el siguiente:

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));
    }
}

 resultado de la operación:

Obviamente, podemos hacer muchas más cosas interesantes con el método de ejecución de MyThread. Descubrir los conceptos de Surface, SurfaceView, SurfaceHolder y SurfaceHolder.Callback, así como la relación entre ellos, debería ser de gran ayuda para que podamos usarlos mejor.

Supongo que te gusta

Origin blog.csdn.net/qq_37381177/article/details/111635096
Recomendado
Clasificación