libro
www.tuyano.com
Google androidプログラミング入門

SurfaceViewによる高速描画 (5/5)

作成:2010-10-31 14:32
更新:2010-10-31 14:32

■ScheduledExecutorServiceによるマルチスレッド処理

SurfaceViewは、独自のスレッドなどを用意することで、UIスレッドにとらわれない高速な処理を実現できます。これは「ScheduledExecutorService」と呼ばれるクラスを利用します。このクラスは、スケジュールを設定し、一定時間ごとに処理を実行するための機能を提供するものです。

このScheduledExecutorServiceは、java.util.concurrentパッケージに用意されているクラスで、「Executors」というクラスに用意されているメソッドを使いインスタンスを取得します。そして、そこでRunnableを引数に渡してメソッドを呼び出し、定期的に処理を実行させます。整理すると、以下のような形で行うことになります。
○ScheduledExecutorServiceの取得
ScheduledExecutorService executor =
        Executors.newSingleThreadScheduledExecutor();

○Runnableの実行
executor.scheduleAtFixedRate( Runnable , 間隔, ディレイ, 時間単位 );
ScheduledExecutorServiceは、「newSingleThreadScheduledExecutor」というメソッドを呼び出すことでインスタンスを取得できます。これは文字通りスケジューリングして処理を実行するためのインスタンスを得るものです。

取得したScheduledExecutorServiceは、「scheduleAtFixedRate」メソッドを呼び出して処理を実行させます。引数に、実行する処理を記述したRunnable、呼び出す間隔と呼び出すまでのディレイ(遅延時間)、それらの時間単位を示す値を指定します。これで、Runnableにあるrunメソッドが一定時間ごとに呼び出されるようになります。これはUIスレッドとは別のスレッドとして実行されるため、他の操作に影響されて呼び出されるまで待たされたりすることもなく、すばやく実行することができます。

簡単な利用例を下のコード欄に掲載しておきましょう。これは先ほどのサンプルの修正版で、描画する赤い円が常に「小さい円→大きい円」という形でアニメーションするようになっています。

ここでは、実行するrunメソッド内で、円の半径を示す変数rの値を増やし、それからdrawを呼び出して表示を更新しています。Viewでは、表示の更新はUIスレッドの中で待たされますが、SurfaceViewではそんなこともなく、ほとんど遅延することなく更新が実行されます。

※プログラムリストが表示されない場合

AddBlockなどの広告ブロックツールがONになっていると、プログラムリスト等が表示されない場合があります。これらのツールをOFFにしてみてください。

●プログラム・リスト●

package jp.tuyano.sample;

import java.util.concurrent.*;

import android.content.Context;
import android.graphics.*;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.view.*;

public class MySurfaceView extends SurfaceView implements
		SurfaceHolder.Callback {

	private SurfaceHolder holder;
	private float x, y, r; // ★rを追加

	public MySurfaceView(Context context) {
		super(context);
		init();
	}

	public MySurfaceView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public MySurfaceView(Context context, AttributeSet attrs,
			int defStyle) {
		super(context, attrs, defStyle);
		init();
	}

	public void init() {
		holder = getHolder();
		holder.addCallback(this);
		setFocusable(true);
		requestFocus();
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder,
			int format, int width, int height) {}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		x = getWidth() / 2;
		y = getHeight() / 2;
		draw();
		startnow(); // ★追加
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			x = event.getX();
			y = event.getY();
			draw();
		}
		return super.onTouchEvent(event);
	}

	public void draw() {
		Canvas c = holder.lockCanvas();
		c.drawColor(Color.WHITE);
		Paint p = new Paint();
		p.setStyle(Style.FILL);
		p.setColor(Color.RED);
		c.drawCircle(x, y, r, p); // ★修正
		holder.unlockCanvasAndPost(c);
	}

	// ★追加メソッド
	public void startnow(){
		ScheduledExecutorService executor =
				Executors.newSingleThreadScheduledExecutor();
		executor.scheduleAtFixedRate(new Runnable() {
			@Override
			public void run() {
				r = r > 50 ? 10 : r + 5;
				draw();
			}
		}, 100, 100, TimeUnit.MILLISECONDS);				
	}

}

※関連コンテンツ

「Google androidプログラミング入門」に戻る