Androidアプリの基本
Android上で実行するゲームは,SDKで開発する限りAndoroidアプリの1つですので,まずはAndoroidアプリの実行を理解しておく必要があります.
Androidアプリの基本単位は画面であるActivityを継承したクラス*1となりますが,このActivityは決まった状態遷移で動作します.
これを,Activityのライフサイクルと呼びます.
以下では,このActivityのライフサイクルとインテントを使って1つのActivityから別のActivityを呼び出す簡単な事例を示します.
Activityのライフサイクル
Activityのライフサイクルは,下図に示すように,onCreate()→onStart()→onResume()実行→onPause()→onStop()→onDestroy()を基本の状態遷移としています.

それぞれの状態がどのように呼ばれるか,については,アプリ作成時に特に意識しておく必要があります.
onCreate()は,Activityの起動時のほか,画面の向きが変化した際にも呼ばれますので,注意が必要です.
onCreate()を単なる初期化メソッドのように書いてしまうと,onCreate()が呼ばれる度にすべてが最初からやり直しになってしまいます.
さらに,画面の向き変化は機器のセンサが感知し,AndroidOSが感知して実行されることになります.このため,機器毎に使用感の差異も生じます.
画面の向きを変化しないようにするためには,画面の向きを固定するようActivityの中で指定するか,どの向きでも対応できるように工夫してから実行中フラグなどでonCreate()の初期化動作を制御する必要があります.
onStart()やonRestart()など,オーバーライドが必要であれば,記述を行います.
onPause(),onStop(),onDestroy()については,OSからの指示で自動的に実行されますが,意図的に実行させることもできます.
onPause()やonRestart()は,例えば,メニューやボタンでアプリの一時停止と再開をする時にそれぞれ呼び出し,ゲームのプレー状態の一時保存と読み出しを実行します.
onStop()とonDestroy()は,finish()というメソッドでonStop()→onDestroy()という順番で呼び出されます.
finish()は,メニューやボタンからアプリを停止させるときに呼び出します.
以上の働きをまとめたものが,ActivityLifeCycleTestクラスです.
以下にコードを示しますが,Eclipse上で開発を行っている場合は,"Android Activity"を「新規(New)」から作成のうえ,コード部分を書き換えることになります.
package jp.ac.bunkyo.a2dgames; /** * Android ActivityのライフサイクルをテストするActivity * @author Hidenao Abe (hidenao@shonan.bunkyo.ac.jp) */ /* Copyright 2013 Hidenao Abe (hidenao@shonan.bunkyo.ac.jp) 本ソースコードは,Apache License Version 2.0(「本ライセンス」)に基づいてライセンスされます。あなたがこのファイルを使用するためには、本ライセンスに従わなければなりません。本ライセンスのコピーは下記の場所から入手できます。 http://www.apache.org/licenses/LICENSE-2.0 適用される法律または書面での同意によって命じられない限り、本ライセンスに基づいて頒布されるソフトウェアは、明示黙示を問わず、いかなる保証も条件もなしに「現状のまま」頒布されます。本ライセンスでの権利と制限を規定した文言については、本ライセンスを参照してください。 (この日本語訳は,http://sourceforge.jp/projects/opensource/wiki/licenses%2FApache_License_2.0によるものです) */ import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; import android.widget.Toast; public class ActivityLifeCycleTest extends Activity { //Activityのライフサイクルと典型的なデバッグ方法の紹介 StringBuilder str_builder = new StringBuilder(); TextView textview; private void logging(String text){ //android.util.Logを使うことで,LogCatタブで指定した文字列が表示される Log.d("LifeCycleTest",text); str_builder.append(text); str_builder.append('\n'); textview.setText(str_builder.toString()); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_activity_life_cycle_test); textview = new TextView(this); textview.setText("Hello!"); setContentView(textview); //Toastは画面上に文字列の入ったボックス型の領域をポップアップする Toast.makeText(this, "LifeCycleTest Created", Toast.LENGTH_SHORT).show(); logging("LifeCycleTest Created"); } @Override public boolean onCreateOptionsMenu(Menu menu) {//Menuボタンを押したときのメニューを有効にする getMenuInflater().inflate(R.menu.activity_activity_life_cycle_test, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) {//Menuボタンを押して出たメニューが選ばれたときの動作を記述 super.onOptionsItemSelected(item); switch(item.getItemId()){ //それぞれのitemの表示はres/menu/activity_activity_life_cycle_test.xmlで行う case R.id.menu_finishing : //強制的にActivityを終了する finish(); return true; } return false; } @Override public void onStart(){ super.onStart(); logging("LifeCycleTest Started"); } @Override public void onRestart(){ super.onRestart(); logging("LifeCycleTest Restarted"); } @Override public void onResume(){ super.onResume(); logging("LifeCycleTest Resumed"); } @Override public void onPause(){ super.onPause(); logging("LifeCycleTest Paused"); if(isFinishing()){ logging("LifeCycleTest Finishing"); } } @Override public void onStop(){ super.onStop(); logging("LifeCycleTest Stoped"); } @Override public void onDestroy(){ super.onDestroy(); logging("LifeCycleTest Destroyed"); } }
複数のActivityを起動するランチャー(明示的インテントの利用)
ここでは,明示的インテントを発行するActivityを作成してみます.
このActivityはListActivityを基に作成していますが,ListActivityはリスト表示に特化したActivityであり,簡単に項目を追加できるため,今回はこれを利用します.
package jp.ac.bunkyo.a2dgames; /** * 各種Activityを明示的インテントによって起動するActivity * @author Hidenao Abe (hidenao@shonan.bunkyo.ac.jp) */ /* Copyright 2013 Hidenao Abe (hidenao@shonan.bunkyo.ac.jp) 本ソースコードは,Apache License Version 2.0(「本ライセンス」)に基づいてライセンスされます。あなたがこのファイルを使用するためには、本ライセンスに従わなければなりません。本ライセンスのコピーは下記の場所から入手できます。 http://www.apache.org/licenses/LICENSE-2.0 適用される法律または書面での同意によって命じられない限り、本ライセンスに基づいて頒布されるソフトウェアは、明示黙示を問わず、いかなる保証も条件もなしに「現状のまま」頒布されます。本ライセンスでの権利と制限を規定した文言については、本ライセンスを参照してください。 (この日本語訳は,http://sourceforge.jp/projects/opensource/wiki/licenses%2FApache_License_2.0によるものです) */ import android.os.Bundle; import android.app.Activity; import android.app.ListActivity; import android.content.Intent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.ArrayAdapter; import android.widget.ListView; import android.support.v4.app.NavUtils; public class IOTestListActivity extends ListActivity {//リストを表示することに特化したListActivityを継承 //リストの対象とするアクティビティのクラス名を列挙(表示とクラス名を分ける場合はMapなどを使用する) String[] test_activities = { "ActivityLifeCycleTest", "SingleTouchTest", "MultiTouchTest", "AccelerometerTest","GeoSensorTest","InnerStorageTest","ExtraStorageTest","IntentSendTest","SoundTest","VibrationTest", "RenderViewTest", "SurfaceViewTest","WebViewTest","HTTPClientTest" }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_iotest_list); //android.R.layoutはgen/R.javaとは異なるので注意↓ setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,test_activities)); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_iotest_list, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: NavUtils.navigateUpFromSameTask(this); return true; } return super.onOptionsItemSelected(item); } protected void onListItemClick(ListView list, View view, int position, long id){ super.onListItemClick(list, view, position, id); String item_name = test_activities[position]; try{ //"Class は raw 型です。総称型 Class<T> への参照は、パラメーター化する必要があります" //という注意が表示されますが,対処の必要はありません. Class class_name = Class.forName("jp.ac.bunkyo.a2dgames."+item_name); Intent intent = new Intent(this,class_name); startActivity(intent); } catch (ClassNotFoundException e){ e.printStackTrace(); } } }
*1:以降,単にActivityと呼びます.