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:
- Start a thread.
- Lock the SurfaceView's canvas.
- Do your drawing.
- 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.
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.
 
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.
- Create a custom view that extends SurfaceViewand implementsRunnable. TheRunnableclass includes arun()method.Implementing therun()method allows a class to execute on a separate thread. Define you class as follows:public class GameView extends SurfaceView implements Runnable{}
- Use the custom view's constructor to initialize your member variables and obtain a reference to the SurfaceView'sSurfaceHolder. Through the holder you can control theSurfacesize and format, edit the pixels in theSurface, and monitor changes to theSurface. Most importantly, the holder is persistent even when aSurfaceis not available (see next step).mSurfaceHolder = getHolder();
- A Surfaceis only available while theSurfaceView's window is visible. If yourSurfaceViewis not always visible, implement thesurfaceCreated(SurfaceHolder)andsurfaceDestroyed(SurfaceHolder)callback methods. Use these methods to discover when theSurfaceis created and destroyed, as the window is shown and hidden.
Now implement the run() method to do the following: 
- Always check whether a valid Surfaceis available.if (mSurfaceHolder.getSurface().isValid()) {
- Lock the canvas. If there is more than one thread drawing on this - Surface, you must put this into a- try/catchblock to handle an- exceptionwhen 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();
- Draw on the canvas.
- 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:
- Ensure that the drawing thread only touches the underlying Surfacewhile it is valid; that is, betweenSurfaceHolder.Callback.surfaceCreated()andSurfaceHolder.Callback.surfaceDestroyed().
- All SurfaceViewandSurfaceHolder.Callbackmethods will be called from the thread running theSurfaceView's window (typically the main thread of the application). These methods need to correctly synchronize with any state that is also touched by the drawing thread.
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. 
Related practical
The related practical documentation is in Creating a SurfaceView object.
Learn more
Android developer docs
- SurfaceViewclass
- SurfaceHolderclass
- ClippingBasiccode sample
- Graphics architecture article
- Sleeping your app is a bad idea
- Choreographerclass
- Hardware acceleration
- Grafika collection of Android graphics tips