11.2: The SurfaceView class

Contents:

When you create a custom view and override its onDraw() method, all drawing happens on the UI thread. Drawing on the UI thread puts an upper limit on how long or complex your drawing operations can be, because your app has to complete all its work for every screen refresh. Each screen refresh usually happens in 16 milliseconds or less, for a typical 60 frames-per-second mobile display. (See the lesson on Performance.)

One solution is to move some of the drawing work to a different thread. One way of doing that is with a SurfaceView.

A SurfaceView is a view in your app's view hierarchy that has its own separate Surface, as shown in the diagram below. This makes it possible to draw to the Surface from a separate thread.

In the context of the Android framework, Surface refers to a lower-level drawing surface whose contents are eventually displayed on the user's screen. To create what the user sees on the screen, the Android system processes your app's layouts and drawing instructions to compose one or more Surfaces, and renders them to the screen. All the views in your view hierarchy are rendered onto one Surface in the UI thread.

To draw onto a Surface:

  1. Start a thread.
  2. Lock the SurfaceView's canvas.
  3. Do your drawing.
  4. Post it to the Surface. You learn more about this below.

The Android system eventually combines all the Surfaces and renders them to the screen, with the SurfaceView's Surface behind the app's Surface.

To fully understand how SurfaceView works requires learning Android Graphics Architecture, which is beyond the scope of this course. The Android developer documentation provides an excellent and much more detailed technical overview in the Graphics Architecture documentation.

Important: SurfaceView is currently not hardware-accelerated. Depending on your app, you may need to consider performance trade-offs. Starting with Android O, you can hardware-accelerate your SurfaceView, which eliminates this specific performance concern.
Note: Other classes are available for when you need more control of your drawing surfaces and operations. Their discussion is beyond the scope of this course. See Graphics architecture for a thorough introduction.

 View Hierarchy showing the <code>Surface</code> used by the views, and the separate <code>Surface</code> used by the <code>SurfaceView</code>..

Working with the SurfaceView class

To create a SurfaceView and draw to it in a separate thread, do the following. See the Creating a SurfaceView object practical for a detailed example.

  1. Create a custom view that extends SurfaceView and implements Runnable. The Runnable class includes a run() method.Implementing the run() method allows a class to execute on a separate thread. Define you class as follows:
     public class GameView extends SurfaceView implements Runnable{}
    
  2. Use the custom view's constructor to initialize your member variables and obtain a reference to the SurfaceView's SurfaceHolder. Through the holder you can control the Surface size and format, edit the pixels in the Surface, and monitor changes to the Surface. Most importantly, the holder is persistent even when a Surface is not available (see next step).
     mSurfaceHolder = getHolder();
    
  3. A Surface is only available while the SurfaceView's window is visible. If your SurfaceView is not always visible, implement the surfaceCreated(SurfaceHolder) and surfaceDestroyed(SurfaceHolder) callback methods. Use these methods to discover when the Surface is created and destroyed, as the window is shown and hidden.

Now implement the run() method to do the following:

  1. Always check whether a valid Surface is available.
     if (mSurfaceHolder.getSurface().isValid()) {
    
  2. Lock the canvas. If there is more than one thread drawing on this Surface, you must put this into a try/catch block to handle an exception when you can't acquire the lock. See the SurfaceView documentation for details and limitations.

     mCanvas = mSurfaceHolder.lockCanvas();
    
     // OR for Android O and later, you can also use lockHardwareCanvas()
     mCanvas = mSurfaceHolder.lockHardwareCanvas();
    
  3. Draw on the canvas.
  4. Unlock the canvas and post its contents to the Surface. Minimize the amount of time the canvas is locked, as there is a performance penalty associated with this.
     mSurfaceHolder.unlockCanvasAndPost(mCanvas);
    

Implement pause() and resume() to stop and start a new thread. For example:

public void pause() {
   mRunning = false;
   try {
       // Stop the thread (rejoin the main thread)
       mGameThread.join();
   } catch (InterruptedException e) {
   }
}

public void resume() {
   mRunning = true;
   mGameThread = new Thread(this);
   mGameThread.start();
}

Handle user-touches or any other data input that affects drawing.

Be aware of these threading semantics:

IMPORTANT: This concept chapter provides only enough information for you to get started with SurfaceView. See the documentation and many publicly available examples if you are interested in learning more about lower-level drawing, game loops, and game development.

The related practical documentation is in Creating a SurfaceView object.

Learn more

Android developer docs

results matching ""

    No results matching ""