Android Graphics : SurfaceView
SurfaceView class is a View that handles a Surface, another class of the Android API.
What is a Surface?
It’s an abstraction of a raw buffer that is used by the screen compositor for rendering that specific View. The screen compositor is the mastermind behind all rendering on Android, and is ultimately responsible for pushing all pixels to the GPU. The Surface can be hardware accelerated in some cases. We don’t care that much about that fact, though. All we need to know is that it is a more
direct way to render things to the screen.
Our goal is it to perform our rendering in a separate thread so that we do not hog the UI thread, which is busy with other things. The SurfaceView class provides us with a way to render to it from a thread other than the UI thread.
SurfaceHolder and Locking
In order to render to a SurfaceView from a different thread than the UI thread, we need to acquire an instance of the SurfaceHolder class, like this:
SurfaceHolder holder = surfaceView.getHolder();
The SurfaceHolder is a wrapper around the Surface, and does some bookkeeping for us. It provides us with two methods:
Canvas SurfaceHolder.lockCanvas();
SurfaceHolder.unlockAndPost(Canvas canvas);
The first method locks the Surface for rendering and returns a nice Canvas instance we can use. The second method unlocks the Surface again and makes sure that what we’ve drawn via the Canvas gets displayed on the screen. We will use these two methods in our rendering thread to acquire the Canvas, render with it, and finally make the image we just rendered visible on the screen. The Canvas we have to pass to the SurfaceHolder.unlockAndPost() method must be the one we received from the SurfaceHolder.lockCanvas() method.
The Surface is not immediately created when the SurfaceView is instantiated. Instead it is created asynchronously. The surface will be destroyed each time the activity is paused and recreated when the activity is resumed again.
SurfaceViewTest.java sourcecode
package
android.example.surfaceview;
import
android.os.Bundle;
import
android.app.Activity;
import
android.content.Context;
import
android.graphics.Bitmap;
import
android.graphics.BitmapFactory;
import
android.graphics.Canvas;
import
android.graphics.Color;
import
android.graphics.Paint;
import
android.graphics.Paint.Style;
import
android.view.SurfaceHolder;
import
android.view.SurfaceView;
import
android.view.WindowManager;
public class
SurfaceViewTest extends Activity {
FastRenderView renderView;
@Override
public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_surface_view);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
renderView = new
FastRenderView(this);
setContentView(renderView);
}
protected void onResume()
{
super.onResume();
renderView.resume();
}
protected void onPause() {
super.onPause();
renderView.pause();
}
class
FastRenderView extends SurfaceView implements Runnable {
Thread
renderThread = null;
SurfaceHolder
holder;
Paint
paint;
Bitmap
icon;
volatile boolean running = false;
public
FastRenderView(Context context) {
super(context);
holder =
getHolder();
paint = new Paint();
// Read
from Drawable
icon = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
}
public void resume() {
running = true;
renderThread = new Thread(this);
renderThread.start();
}
public void pause() {
running = false;
while(true) {
try {
renderThread.join();
}
catch (InterruptedException e) {
// retry
}
}
}
public void run() {
while(running) {
if(!holder.getSurface().isValid())
continue;
Canvas
canvas = holder.lockCanvas();
canvas.drawRGB(255,
0, 0);
// Draw
Line
paint.setColor(Color.WHITE);
canvas.drawLine(0,
0, canvas.getWidth()-1, canvas.getHeight()-1, paint);
// Draw
Rectangle
paint.setStyle(Style.FILL);
paint.setColor(0x77ffffff); // White
canvas.drawRect(100,
100, 400, 400, paint);
// Draw
Circle
paint.setStyle(Style.STROKE);
paint.setColor(0xff00ff00); // Green
canvas.drawCircle(canvas.getWidth()
/ 2, canvas.getHeight() / 2, 80, paint);
canvas.drawBitmap(icon, 140, 500, null);
holder.unlockCanvasAndPost(canvas);
}
}
}
}
Android Graphics SurfaceView Example Code