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; } }