前回の「タッチ入力とマルチスレッド」の記事では、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を配置しているだけです。

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