SurfaceView is a special kind of view in Android. The biggest difference between it and TextView and Button is that it is not on the same view layer as its view container, and its UI display can be done in a separate thread, so the drawing of SurfaceView does not affect the main thread. surfaceView does not affect the main thread. Combining these features, SurfaceView is generally used to implement dynamic or complex images and animations.
MVC framework for SurfaceView
The relationship between Surface, SurfaceHolder, and SurfaceView is essentially what is known as MVC, or Model-View-Controller. Model means model, or data model, or more simply, data, which is Surface in this case; View means view, which represents the user interaction interface, which is SurfaceView in this case; SurfaceHolder can obviously be understood as the Controller in MVC. (controller).
Unlike normal controls, SurfaceView can run outside the main thread and does not need to respond to user input in a timely manner, nor does it cause ANR problems. surfaceView is generally used for complex UI and efficient image display for games, video, photography, etc., which require a separate thread for image processing.
Analyze the source code
Analyze the Surface, SurfaceHolder, and SurfaceView classes
First, look at the Surface class, which implements the Parcelable interface for serialization (here it is mainly used to pass surface objects between processes) and is used to handle the data in the screen display buffer, which is commented in the source code as: Handle onto a raw buffer that is being managed by the screen compositor. Surface is a handle to a raw buffer that is being managed by the screen compositor.
A handle to the raw buffer managed by the screen compositor (similar to a handle) - Explanation of the term: Handle, English: HANDLE, the memory address of a data object is obtained after it enters memory, but the memory address is not fixed and a handle is needed to store the memory address where the content is located. In terms of data type it is just a 32-bit (or 64-bit) unsigned integer. - Surface acts as a handle to get the source buffer and its contents - the raw buffer is used to store the pixel data of the current window - so it is clear that Surface is the place for drawing in Android, specifically it is the Canvas in Surface Surface defines the Canvas object related to the canvas
Java, drawing is usually done on a Canvas object, Surface also contains a Canvas object, here CompatibleCanvas is an internal class in Surface.java, which contains a matrix object Matrix (variable name mOrigMatrix). The Matrix Matrix is a memory area where all the drawing operations for the View are stored. Surface has an internal class CompatibleCanvas, which is designed to be compatible with Android screens of various resolutions and to handle different image data according to the resolution of different screens.
Two important methods
It is important to note that the lockCanvas is not the lockCanvas and unlockCanvasAndPost methods that are called by the SurfaceHolder object when the SurfaceView is actually used for drawing. The methods used in the actual example are wrapped inside the SurfaceView after wrapping these two methods. - lockCanvas(…) + Gets a Canvas object for drawing into this surface. + After drawing into the provided Canvas, the caller must invoke After drawing into the provided Canvas, the caller must invoke unlockCanvasAndPost to post the new contents to the surface. After drawing a frame of data, the unlockCanvasAndPost method needs to be called to unlock the canvas and then post the drawn image to the current screen. When a Canvas is being drawn, it is locked, meaning it must wait for the frame being drawn to finish and unlock the canvas before doing anything else + The actual locking of the Canvas is done at the jni level - unlockCanvasAndPost(…) + Posts the new contents of the Canvas to the surface and releases the Canvas. The actual release process is done at the jni layer)
Surface’s lockCanvas and unlockCanvasAndPost methods end up calling the jni layer methods to handle the process. /frameworks/native/libs/gui/Surface.cpp /frameworks/base/core/jni/android_view_Surface.cpp
SurfaceHolder SurfaceHolder is actually an interface that acts as a controller.
Let’s see what the commentary says
- Abstract interface to someone holding a display surface.
- Allows you to control the surface size and format, edit the pixels in the surface, and monitor changes to the surface. The bare bones Controller role that controls the size and format of the Surface, monitors changes to the Surface (and handles changes to the Surface in a callback function)
- When using this interface from a thread other than the one running its SurfaceView, you will want to carefully read the methods - When using this interface from a thread other than the one running its SurfaceView, you will want to carefully read the methods of Callback.surfaceCreated() If you are using a subthread to handle the drawing of the SurfaceView, you will need to use the surfaceCreated method of the key interface Callback, which is described next. As you can see in the example given earlier, the thread that draws the animation is opened in the surfaceCreated method
Critical Interfaces Callback
Callback is an interface inside the SurfaceHolder, which is implemented in the example to control the thread that draws the animation.
There are three methods in the interface -
public void surfaceCreated(SurfaceHolder holder); + Surface is called the first time it is created, for example when the SurfaceView goes from the invisible state to the visible state + Between the time this method is called and the time the Surface objects can be manipulated between the time this method is called and the time the surfaceDestroyed method is called, which in the case of SurfaceView means that if the SurfaceView is visible on the interface, it can be drawn and animated + Another thing to note here is that Surface If you have already rendered the data in another thread, you don’t need to open a thread here to draw the Surface -
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height); + The surface will be called when the size and format change, for example, if you need to handle Sufface images and animations when switching between horizontal and vertical screens, you need to implement it here + This method will be called at least once after the surfaceCreated -
public void surfaceDestroyed(SurfaceHolder holder); + Surface is called when it is destroyed, e.g. when the SurfaceView is invisible from the visible state + After this method is called, no more operations can be performed on the Surface object. So you need to make sure that the drawing thread does not operate on the Surface after this method is called, otherwise it will report an error
SurfaceView, which is the View used to display the Surface data, is used to see the Surface data through the SurfaceView.
Analyze the comments on the SurfaceView in the source code
- Provides a dedicated drawing surface embedded inside of a view hierarchy.
- the SurfaceView punches a hole in its window to allow its surface to be displayed. SurfaceView
- The Surface will be created for you while the SurfaceView’s window is visible.
- you should implement SurfaceHolder.Callback#surfaceCreated and SurfaceHolder.Callback#surfaceDestroyed to discover when the Surface is created and destroyed as the window is shown and hidden.
The example shows how to use the SurfaceView
- you need to implement the
Callbackto open a thread to draw the animation frame by frame.
- you need to end the drawing thread in the
SurfaceHolder.Callbackand call the
lockCanvasmethod needs to be called before each frame of the drawing thread starts to lock the canvas for drawing
- After drawing a frame of data, you need to call the
unlockCanvasAndPostmethod to submit the data to display the image
Some problems that may be encountered
Why does a SurfaceView display a black area when placed in a layout file without a task image drawn?
The reason for this phenomenon can be seen in the draw and dispatchDraw methods of the SurfaceView, where the windownType variable is initialized to WindowManager. MEDIA, so the entire Canvas will be painted black during the process of creating and drawing this View