SurfaceViewを使えば、高速な描画を行うことができる。
この前に作成した、自前でアニメーションをする処理や、ゲームなどの描画にはSurfaceViewを使った方が良いだろう。
SurfaceViewのプログラミングはViewのみで描画するよりも、少しだけ複雑になる。
以下にSurfaceViewのプログラミングの例を示す。
public class MySurfaceView extends SurfaceView {
private ScheduledExecutorService ses = null;
private final SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
ses.shutdown();
ses = null;
Toast.makeText(getContext(), "surfaceDestroyed", Toast.LENGTH_SHORT).show();
}
@Override
public void surfaceCreated(final SurfaceHolder holder) {
Toast.makeText(getContext(), "surfaceCreated", Toast.LENGTH_SHORT).show();
ses = Executors.newSingleThreadScheduledExecutor();
ses.scheduleAtFixedRate(new Runnable() {
private final int ox = 100;
private final int oy = 100;
private final int r = 50;
private int count = 0;
private final Paint txtPaint = new Paint();
private final Paint figPaint = new Paint();
{
txtPaint.setAntiAlias(true);
txtPaint.setTextSize(12);
figPaint.setAntiAlias(true);
figPaint.setStyle(Style.STROKE);
}
@Override
public void run() {
final Canvas canvas = holder.lockCanvas();
if (canvas != null)
{
// 描画する
canvas.drawColor(Color.WHITE);
canvas.drawText(
"" + count++, 0, txtPaint.getTextSize(), txtPaint);
final double radians = Math.toRadians(count % 360);
final int cx = (int)(ox + r * Math.cos(radians));
final int cy = (int)(oy + r * Math.sin(radians));
canvas.drawLine(ox, oy, cx, cy, figPaint);
canvas.drawOval(
new RectF(ox - r , oy - r, ox + r, oy + r),
figPaint);
holder.unlockCanvasAndPost(canvas);
}
}
}, 0, 16, TimeUnit.MILLISECONDS );
}
@Override
public void surfaceChanged(
SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
Toast.makeText(getContext(), "surfaceChanged", Toast.LENGTH_SHORT).show();
}
};
/**
* コンストラクタ
* @param context
*/
public MySurfaceView(Context context) {
super(context);
// コールバックの登録
getHolder().addCallback(callback);
}
}
ポイントは、まずSurfaceViewを継承することである。
そして、getHolder()メソッドでSurfaceHolderを取得し、そこにコールバックを登録しているところである。サンプルでは83行目がその処理にあたる。
このコールバックはサーフェイスが作られたときや破壊されるときに呼ばれるので、そのタイミングで描画処理の初期化/終了処理を行う。
描画処理は別にスレッドを立てている。例ではExecutorsを使ってスレッドを取得しているが、もちろん普通のThreadクラスでかまわない。
そして、43行目からのRunnableのrun()メソッド内で、スレッドから直接Viewに描画する。
このときに必要なのはSurfaceHolderのlockCanvas()メソッドでロックされたcanvasを取得し、それに対して描画を行って、unlockCanvasAndPost()メソッドでロックを解除することである。この基本的な流れが分かれば、描画のプログラミング自体は普通のViewのものと変わらないので、色々と応用できるだろう。
Activityのプログラムは、単に上で作った自分のSurfaceViewを登録しているだけである。
public class MainActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MySurfaceView(this));
}
}
サンプルは、円の中を直線が回転するプログラムである。
実行結果は以下のようになる。

[slmplayer uri=”2011/06/20110625_device.wmv”]