SurfaceViewを仕様していると描画用のスレッド等を使用することになります。 Threadを使用すると煩雑なことが多いです。 そこでThreadをカスタマイズしたクラスを作成します。
githubにコードを置きました。
1. Threadの使い方
Threadの簡単な使い方は以下の通りです。
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
/** Do something in Thread. */
}
});
/** Start thread. */
thread.start();
/** Do something out of Thread. */
/** Stop thread. */
/** thread.stop() does not work. */
thread.interupt();
thread = null;
Runnableインターフェースのrunメソッドにスレッドで実行したい処理を記載 します。
Thread.start()を実行後、スレッドが動き出す機会が得られます。
Thread.stop()はdepricatedとなり、今や使用できません。 Thread.interupt()を実行すると、run()メソッド内でThread.sleep()を実行し た際にrunメソッド内でInterruptedExceptionが発生し、スレッドの停止を通 知することができます。
2. Runnableクラス
Runnableクラスのドキュメントによれば、RunnableインターフェースはThread クラスを拡張することなくスレッドを使用させる為のもので、Threadクラスを 拡張すべきではないと記載されています。 http://docs.oracle.com/javase/jp/6/api/java/lang/Runnable.html
しかし、Runnableクラスが複雑になりがちな点がデメリットとしてあると思い ます。例えば、描画の無限ループをsleepを交えながら実行する場合、逐一 Runnableクラスのrunメソッドで定義しなくてはなりません。 そこで、無限ループをsleepを交えながら実行できるカスタマイズされたスレッ ドクラスを定義します。
3. Threadクラスのカスタマイズ
Threadクラスを拡張したクラスと、拡張したThreadクラスのインスタンスを内 部で持つラッパークラスを作成します。 ラッパークラスのstartメソッドにて、拡張したThreadクラスを開始し、stop メソッドで拡張したThreadクラスのinterupt()実行と参照を外します。
public class WrapperThread {
public class ExtendedThread extends Thread {
public ExtendedThread() { /** Do nothing. */ }
public void run() {
/** Start loop. */
while (true) {
/** Do something. */
try {
/** Sleep. */
Thread.sleep(sleepTime);
} catch (Exception e) {
/** Stop loop. */
break;
}
}
}
}
public void start() {
/** Start thread. */
mThread = new ExtendedThread();
mThread.start();
}
public void start() {
/** Stop thread. */
mThread.interupt();
mThread = null;
}
}
加えて、sleepの秒数をFPS換算させ、Runnableを動的に変更できるようにした のが以下のコードとなります。 ラッパークラス生成後、拡張クラスの状態に関わらず、Runnableは動的に追加 と削除ができます。
/**
* Wrapper thread class for java.lang.Thread. This class can be recycled. Once
* Sample thread created, SampleThread.start() and SampleThread.stop() can be
* used repeatedly.
*/
public class SampleThread {
/**
* Extended thread class for java.lang.Thread with flag for stopping thread.
* This class cannot be recycled. SampleThread class will hide this recycle.
*/
public class SafeStopThread extends Thread {
public SafeStopThread() {
/** Do not call super(). */
}
@Override
public void run() {
/** Loop start. */
while (true) {
long prevTime = System.currentTimeMillis() / 1000;
synchronized (mRunnable) {
for (Runnable runnable : mRunnable)
runnable.run();
}
long postTime = System.currentTimeMillis() / 1000;
long sleepTime = postTime - prevTime;
/** Sleep at least 1 msec for avoiding ANR. */
if (sleepTime >= mSleepTime)
sleepTime = 1;
try {
Thread.sleep(sleepTime);
} catch (Exception e) {
break;
}
}
/** Loop end. */
}
}
/** Runnable done in thread loop. */
private final List<Runnable> mRunnable;
/** Extended thread class. */
private SafeStopThread mThread;
/** Sleep time each thread loop. */
private final long mSleepTime;
/**
* @param FPS
* Frame per second for thread loop.
*/
public SampleThread(int FPS) {
mRunnable = new ArrayList<Runnable>();
mSleepTime = FPS / 1000;
}
public void addRunnable(Runnable runnable) {
synchronized (mRunnable) {
mRunnable.add(runnable);
}
}
public void removeRunnable(Runnable runnable) {
synchronized (mRunnable) {
mRunnable.remove(runnable);
}
}
public void start() {
mThread = new SafeStopThread();
mThread.start();
}
public void stop() {
/** Throw InterruptedException. */
mThread.interrupt();
mThread = null;
}
}