SurfaceView最小プログラム

前回の「タッチ入力とマルチスレッド」の記事では、SurfaceViewを使ったプログラムで発生する、マルチスレッドの問題を取り上げました。
タッチ入力とマルチスレッド(1)
タッチ入力とマルチスレッド(2)
前回の記事のサンプルコードは、ほぼそのままSurfaceViewを使ったゲームの基礎として使用できます。
ただまだ一つ問題があります。
onPause、onResumeに対応していないため、ホームボタンでアプリがバックグラウンドに回っても、ゲームが停止しません。
今回はその対応を行った、最小限のSurfaceViewプログラムを紹介します。

では少し長いですがプログラムの全文です。

public class CActivityMain extends Activity implements Runnable, View.OnTouchListener
{
	static public final class CTouchEvent
	{
		public int		mAction;
		public float	mX;
		public float	mY;
		
		CTouchEvent(MotionEvent iEvent)
		{
			mAction = iEvent.getAction();
			mX = iEvent.getX();
			mY = iEvent.getY();
		}
	}

	private List<CTouchEvent> mEventListMain = new ArrayList<CTouchEvent>();
	private List<CTouchEvent> mEventListUI = new ArrayList<CTouchEvent>();
	private SurfaceView mView;
	private Thread mThread;
	private volatile boolean mThreadRun;
	private float mX;
	private float mY;
	
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		mView = (SurfaceView)findViewById(R.id.surfaceView1);
		mView.setOnTouchListener(this);
	}

	@Override
	protected void onResume()
	{
		super.onResume();
		mThreadRun = true;
		mThread = new Thread(this);
		mThread.start();
	}

	@Override
	protected void onPause()
	{
		super.onPause();
		mThreadRun = false;
		while(true)
		{
			try
			{
				mThread.join();
				break;
			}
			catch (InterruptedException iException)
			{
			}
		}
		mThread = null;
	}

	@Override
	public void run()
	{
		SurfaceHolder aHolder = mView.getHolder();
		Paint aPaint = new Paint();
		aPaint.setColor(Color.RED);
		while(mThreadRun)
		{
			if(aHolder.getSurface().isValid())
			{
				synchronized (this)
				{
					mEventListMain.clear();
					List<CTouchEvent> aTemporary = mEventListMain;
					mEventListMain = mEventListUI;
					mEventListUI = aTemporary;
				}
				for(CTouchEvent aTouchEvent : mEventListMain)
				{
					if(aTouchEvent.mAction == MotionEvent.ACTION_DOWN)
					{
						mX = aTouchEvent.mX;
						mY = aTouchEvent.mY;
					}
				}
				Canvas aCanvas = aHolder.lockCanvas();
				aCanvas.drawColor(Color.WHITE);
				aCanvas.drawCircle(mX, mY, 50.0f, aPaint);
				aHolder.unlockCanvasAndPost(aCanvas);
			}
		}
	}

	@Override
	public boolean onTouch(View iView, MotionEvent iEvent)
	{
		synchronized (this)
		{
			mEventListUI.add(new CTouchEvent(iEvent));
		}
		return true;
	}
}

ほとんどは「タッチ入力とマルチスレッド」の記事のものと同じです。
今回は変更点のみ解説します。

まずonPause、onResumeでどのような処理を行わなくてはいけないかを説明します。
ホームボタンが押されるとonPauseが呼ばれます。
onPauseではゲーム処理を停止させる必要がありますが、停止といっても要はスレッドを終了させてしまえばよいわけです。
そしてアプリに復帰した際にonResumeが呼ばれるので、そこでもう一度スレッドを開始すればゲームは再開します。
ゲームに必要なデータはスレッドが持っているわけではないため、スレッドが終了しても、ゲーム中の値が消えたりすることはありません。

ということで、まずはonResumeです。

	@Override
	protected void onResume()
	{
		super.onResume();
		mThreadRun = true;
		mThread = new Thread(this);
		mThread.start();
	}

スレッドを作成して、開始しているだけです。
mThreadRunにtrueを設定していますが、これはrun()内のループがwhile(true)ではなく、while(mThreadRun)になっているためです。
つまりmThreadRun=falseにすればrun()が終了するようにしています。
ひとつ注意点として、onResumeはアプリを再開ではなく、開始した時にも呼ばれます。
そのためonCreateではスレッドの開始をしていません。

次にonPauseです。

	@Override
	protected void onPause()
	{
		super.onPause();
		mThreadRun = false;
		while(true)
		{
			try
			{
				mThread.join();
				break;
			}
			catch (InterruptedException iException)
			{
			}
		}
		mThread = null;
	}

mThreadRunをfalseにして、mThread.join()でスレッドの終了を待っています。
(joinの例外は発生することはないはずなので、無視します)

以上でonPause、onResumeへの対応は終わりです。
今回のサンプルコードをベースにすることで、SurfaceViewを使ったゲーム作成を、とりあえず開始することができます。

最後に一応、レイアウトファイル(activity_main.xml)も載せておきます。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".CActivityMain" >

    <SurfaceView
        android:id="@+id/surfaceView1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</RelativeLayout>

レイアウト全体にSurfaceViewを配置しているだけです。

SurfaceView最小プログラム」への1件のフィードバック

  1. ピンバック: このサイトの改修について | takts – tak training site

コメントを残す

メールアドレスが公開されることはありません。