Android ネイティブアプリは、いくつかのメッセージを処理することにより、アプリ起動時の初期化や、一時停止などが制御されます。 Windows とは異なり、非常に少ない種類のメッセージのみが用意されているようです。
ここでは、この処理について、検討しています。 なお、アプリ独自のものも追加することができるようですが、ここでは検討していません。
私は Windows プログラマですので、
このページ、および開発関連ページは、PC向けデザインとなっております。 画面サイズの小さいスマホでは、快適な表示が得られませんので、ご了承ください。
ご利用に際しては、必ずプライバシーポリシー(免責事項等)をご参照ください。
また、本サイトが初めての方は、まずこのページの注意事項をご覧ください。
main.cpp の android_main 関数の最初に、次のような部分があります。
state->onAppCmd = engine_handle_cmd;
state は、android_main 関数に渡されている引数で、struct android_app* です。 これにより、APP_CMD_*** メッセージは、engine_handle_cmd 関数で処理される、 ということになります。
engine_handle_cmd 関数は、同じ main.cpp で定義されています。
static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
と定義されていて、第2引数の cmd が、メッセージを示しています。 型からわかるように、メッセージと言っても整数値です。
自動生成されたコードでは5種類しかハンドルしていませんが、その定義を調べると、まだあります。
すべての(システム)メッセージは
android_native_app_glue.h で定義されています。
このファイルは、ネイティブアプリと Android システムをつなぎあわせる(=
enum { /** * メイン スレッドからのコマンド: AInputQueue が変更されました。このコマンドの処理の際、 * android_app->inputQueue は新しいキュー (または NULL) * に更新されます。 */ APP_CMD_INPUT_CHANGED, /** * メイン スレッドからのコマンド: 新しい ANativeWindow を使用する準備ができました。このコマンドを受信する際、 * android_app->window に新しいウィンドウ画面が * 含まれます。 */ APP_CMD_INIT_WINDOW, (とりあえず以降は略)
初期状態で、engine_handle_cmd 関数で処理されているメッセージは、 APP_CMD_SAVE_STATE、APP_CMD_INIT_WINDOW、APP_CMD_TERM_WINDOW、APP_CMD_GAINED_FOCUS、APP_CMD_LOST_FOCUS です。
基本的には、必要なメッセージを処理するなら処理して、この関数を終了すればいいようです。
メッセージは単なる数値で、android_native_app_clue.h で enum で定義されているだけですので、定義順に列挙します。 緑の文字は、生成されたコードにあるコメントです。
APP_CMD_INPUT_CHANGED(値0)
アプリ起動時に必ず呼び出されています。今のところ、特に何もする必要はないように思えます。
APP_CMD_INIT_WINDOW(値1)初期状態に実装あり
アプリ起動時、ウィンドウの用意ができたら呼び出されています。
初期状態の実装は次のようになっていますので、ウィンドウ関連の初期化を各関数で実行する必要があります。
if (engine->app->window != NULL) { engine_init_display(engine); engine_draw_frame(engine); }
APP_CMD_TERM_WINDOW(値2)初期状態に実装あり
アプリが一時停止するときに呼び出されています?
初期状態の実装は次のようになっていますので、ウィンドウ関連のクリーンアップを実行する必要があります。
engine_term_display(engine);
APP_CMD_WINDOW_RESIZED(値3)
古い Android であれば、実行中に画面サイズが変わることはないと思いますが、新しい Android ではあるかも知れません。 また、画面の縦横が自動回転されたときにこのメッセージが来るかどうかは、今はわかりません。 何かわかった時には、追記します。
APP_CMD_WINDOW_REDRAW_NEEDED(値4)
現時点では不明です。 何かわかった時には、追記します。
APP_CMD_CONTENT_RECT_CHANGED(値5)
古い Android であれば、実行中に画面サイズが変わることはないと思いますが、新しい Android ではあるかも知れません。 何かわかった時には、追記します。
APP_CMD_GAINED_FOCUS(値6)初期状態に実装あり
アプリ起動時、一連のメッセージの最後に呼び出されています。
初期状態の実装では、加速度計の監視を開始するようになっていますので、
センサー不要のときは省電力のために止めて、自分がアクティブになったとき、スタート(再スタート)すべきです。
APP_CMD_LOST_FOCUS(値7)初期状態に実装あり
初期状態の実装では、加速度計の監視を停止し、画面の描画を停止するようになっています。
Android OS のバージョンが新しいとマルチウィンドウができるようですが、そのへんがどうなっているかは、今はわかりません。
APP_CMD_CONFIG_CHANGED(値8)
現時点では不明です。 何かわかった時には、追記します。
APP_CMD_LOW_MEMORY(値9)
このメッセージが来た時にどう対処すべきかは、現時点では不明です。 アプリ実行中であれば他のアプリが強制終了になったり、使用中のメモリが解放されたりするようですが、 これはもしかして他に実行中のアプリがメモリ不足になったときに呼び出されるのかもしれません。 何かわかった時には、追記します。
APP_CMD_START(値10)
Java を使った、ネイティブではないアプリでいうところの onStart に相当するメッセージと思っています。
ウィンドウの作成などよりもまず先に、一番最初に通知されています。
自動生成されたコードには実装はありませんが、アプリ再開時にも呼び出されていますので、初期化を行う部分と考えられます。
APP_CMD_RESUME(値11)
上記コメントでは「再開」とありますが、アプリ起動時にも、APP_CMD_START に続いて送信されています。
APP_CMD_SAVE_STATE(値12)初期状態に実装あり
初期状態の実装は次のようになっています。
engine->app->savedState = malloc(sizeof(struct saved_state)); *((struct saved_state*)engine->app->savedState) = engine->state; engine->app->savedStateSize = sizeof(struct saved_state);
main.cpp の最初の部分で定義されている、struct saved_state 構造体をまるごと保存しています。
この構造体は、最小限のサイズに抑えるべき、ということになります。
アプリ再開のときには、android_main 関数の最初のほう、
メインループより前に次のようなコードがありますが、まだ詳細を理解していません。
if (state->savedState != NULL) { // 以前の保存状態で開始します。復元してください。 engine.state = *(struct saved_state*)state->savedState; }
APP_CMD_PAUSE(値13)
アプリ実行中にホーム画面に戻ったりするなど、「ポーズ」状態になるとき、送信されてきます。 何をすべきなのかは、今はわかりません。 何かわかった時には、追記します。
APP_CMD_STOP(値14)
アプリ実行中にホーム画面に戻ったりするなど、「ポーズ」状態になり、一時停止になるときに送信されるようです。 新しい Android の場合には、意味があるかもしれません。 何かわかった時には、追記します。
APP_CMD_DESTROY(値15)
確保したメモリのクリーンアップ等、行わなければいけません。
アプリ起動時のメッセージ送信順を記録しておきます。 Android のバージョン 4.4.2 での調査結果です。
アプリ起動時には、APP_CMD_START、APP_CMD_RESUME、APP_CMD_INPUT_CHANGED、APP_CMD_INIT_WINDOW、 APP_CMD_GAINED_FOCUS と受領しているようです。受領順に、記述します。
APP_CMD_START
起動時の処理を行うようですが、自動生成されたコードに何もありませんでしたので、とりあえず私は何もしていません。
ここではまだ、ウィンドウ作成等は行われていません。
Java コードでいう、onStart 関数に相当すると考えています。
APP_CMD_RESUME
自動生成されたコードのコメントには「再開」とありますが、アプリ起動時にも送信されています。
Java コードでいう、onResume 関数に相当すると考えています。とりあえず私は何もしていません。
APP_CMD_INPUT_CHANGED
AInputQueue が変更された、ということで、android_app->inputQueue に 正しい値が設定された、以降参照できる、という解釈で良さそうです。
APP_CMD_INIT_WINDOW
自動生成されたコードでは、engine_init_display 関数と、
engine_draw_frame 関数を呼び出しています。
画面(ウィンドウ)のサイズが、
engine->width と engine->height に設定されているので、
私はここで、それを記録し、縦長(ポートレート)なのか、横長(ランドスケープ)なのかを判定したりしています。
APP_CMD_GAINED_FOCUS
ウィンドウ(アプリ)がアクティブになったときに送信されています。 起動時だけでなく、再開時にも送信されていますので、サウンドの初期化など、多少時間がかかるかもしれない処理を入れてみました。
ここまで受領し、処理したら、あとは自由にしていいようです。
ホームボタン(〇ボタン)を押すと、アプリは中断され、ホーム画面に戻ります。
アプリ中断時のメッセージ送信順を記録しておきます。 Android のバージョン 4.4.2 での調査結果です。
APP_CMD_PAUSE
アクティビティが停止すると、まず最初に送信されてきています。
自動生成されたコードにはありませんでしたので、処理しなくてもいいのかな、と考えています。
APP_CMD_LOST_FOCUS
少なくとも Android 4.4.2 では、アプリがフォーカスを失うということは、前面にいなくなることですので、 BGMを止めるコードを入れています。
APP_CMD_TERM_WINDOW
ウィンドウが破棄される、ということですので、読み込んでいたテクスチャを解放しています。
再開時に再読み込みになりますが、何よりメモリを解放しないといけないと思います。
main.cpp の engine_term_display 関数は、そのままとしています。
APP_CMD_SAVE_STATE
自動生成されたコードでは、struct saved_state 構造体をまるごと保存しています。
アプリ作成に向けて調査中の現時点では、ここで保存した情報を
APP_CMD_STOP
Java コードでいう、onStop 関数に相当すると思われます。
私は特に何もしていません。
アプリを再開させたときののメッセージ送信順を記録しておきます。 Android のバージョン 4.4.2 での調査結果です。
APP_CMD_START
アプリ起動時と同じく、このメッセージが来ました。
APP_CMD_RESUME
アプリ起動時と同じく、このメッセージが来ました。
APP_CMD_INPUT_CHANGED
アプリ起動時には送信されるこのメッセージは、再開時には送信されてきていません。
APP_CMD_INIT_WINDOW
アプリ起動時と同じく、このメッセージが来ました。 破棄されたウィンドウを再度準備します。
APP_CMD_GAINED_FOCUS
アプリ起動時と同じく、このメッセージが来ました。
アプリがアクティブな状態から、いきなり終了にすることはできないと思います。 いったん中断と同じようにメッセージを処理し、クリーンアップしておきます。
本当の終了時(使用したアプリ一覧から削除)するときには、ログ出力できるメッセージは何も来ていないようでした。 現在の(ファイルへの)ログ出力コードが、ウィンドウが終了するとログを出せなくなるため、見えないだけと思われます。
Android 開発に関する情報をまとめた Android 開発トップ もご覧ください。