このサイトでは、分析、カスタマイズされたコンテンツ、および広告に Cookie を使用します。このサイトを引き続き閲覧すると、Cookie の使用に同意するものと見なされます。
Hi, Developers,
straightapps.com
作成 September 18, 2018
トップページ > Android 開発トップ > APP_CMD_*** メッセージ

ここでは、APP_CMD_*** メッセージの処理について検討します。

Android ネイティブアプリは、いくつかのメッセージを処理することにより、アプリ起動時の初期化や、一時停止などが制御されます。 Windows とは異なり、非常に少ない種類のメッセージのみが用意されているようです。 ここでは、この処理について、検討しています。 なお、アプリ独自のものも追加することができるようですが、ここでは検討していません。

私は Windows プログラマですので、Windows 風の実装をしたかったので調査し、コードを作成しました。 まずは、APP_CMD_ で始まるメッセージがどのように通知されるのかを調べました。

このページ、および開発関連ページは、PC向けデザインとなっております。 画面サイズの小さいスマホでは、快適な表示が得られませんので、ご了承ください。
ご利用に際しては、必ず
プライバシーポリシー(免責事項等)をご参照ください。
また、本サイトが初めての方は、まずこのページの注意事項をご覧ください。

APP_CMD_ の処理について

投稿 September 18, 2018

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 システムをつなぎあわせる(= glue)役割をしています。

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 です。

基本的には、必要なメッセージを処理するなら処理して、この関数を終了すればいいようです。

▲ページ先頭へ

APP_CMD_ メッセージの種類

投稿 September 18, 2017

メッセージは単なる数値で、android_native_app_clue.h で enum で定義されているだけですので、定義順に列挙します。 緑の文字は、生成されたコードにあるコメントです。

APP_CMD_INPUT_CHANGED(値0)

メイン スレッドからのコマンド: AInputQueue が変更されました。このコマンドの処理の際、 android_app->inputQueue は新しいキュー (または NULL)に更新されます。

アプリ起動時に必ず呼び出されています。今のところ、特に何もする必要はないように思えます。

APP_CMD_INIT_WINDOW(値1)初期状態に実装あり

メイン スレッドからのコマンド: 新しい ANativeWindow を使用する準備ができました。 このコマンドを受信する際、android_app->window に新しいウィンドウ画面が含まれます。

アプリ起動時、ウィンドウの用意ができたら呼び出されています。
初期状態の実装は次のようになっていますので、ウィンドウ関連の初期化を各関数で実行する必要があります。

if (engine->app->window != NULL) {
	engine_init_display(engine);
	engine_draw_frame(engine);
}

APP_CMD_TERM_WINDOW(値2)初期状態に実装あり

メイン スレッドからのコマンド: 既存の ANativeWindow を終了する必要があります。 このコマンドを受信する際にも android_app->window には引き続き既存のウィンドウが含まれており、 android_app_exec_cmd を呼び出した後に NULL に設定されます。

アプリが一時停止するときに呼び出されています?
初期状態の実装は次のようになっていますので、ウィンドウ関連のクリーンアップを実行する必要があります。

engine_term_display(engine);

APP_CMD_WINDOW_RESIZED(値3)

メイン スレッドからのコマンド: 現在の ANativeWindow のサイズが変更されました。 新しいサイズを使用して再描画してください。

古い Android であれば、実行中に画面サイズが変わることはないと思いますが、新しい Android ではあるかも知れません。 また、画面の縦横が自動回転されたときにこのメッセージが来るかどうかは、今はわかりません。 何かわかった時には、追記します。

APP_CMD_WINDOW_REDRAW_NEEDED(値4)

メイン スレッドからのコマンド: このシステムでは、現在の ANativeWindow が再描画される必要があります。 一時的な描画の不具合を回避するためには、android_app_exec_cmd() に渡す前にウィンドウを再描画する必要があります。

現時点では不明です。 何かわかった時には、追記します。

APP_CMD_CONTENT_RECT_CHANGED(値5)

メイン スレッドからのコマンド: ウィンドウのコンテンツ領域が変更 (表示または非表示のソフト入力ウィンドウなどから) されました。新しいコンテンツ領域は、android_app::contentRect にあります。

古い 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)初期状態に実装あり

メイン スレッドからのコマンド: 必要に応じて後で復元できるように、アプリが新しい保存状態を生成する必要があります。 状態を保存した場合は malloc を割り当て、android_app.savedStateSize のサイズで android_app.savedState に配置します。 後で解放されます。

初期状態の実装は次のようになっています。

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)

メイン スレッドからのコマンド: アプリのアクティビティが破棄されており、 続行する前に、アプリ スレッドがクリーン アップして終了するのを待機しています。

確保したメモリのクリーンアップ等、行わなければいけません。

▲ページ先頭へ

アプリ起動時の呼び出し順

投稿 September 18, 2018

アプリ起動時のメッセージ送信順を記録しておきます。 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->widthengine->height に設定されているので、 私はここで、それを記録し、縦長(ポートレート)なのか、横長(ランドスケープ)なのかを判定したりしています。

APP_CMD_GAINED_FOCUS

ウィンドウ(アプリ)がアクティブになったときに送信されています。 起動時だけでなく、再開時にも送信されていますので、サウンドの初期化など、多少時間がかかるかもしれない処理を入れてみました。

ここまで受領し、処理したら、あとは自由にしていいようです。

▲ページ先頭へ

アプリ中断時の呼び出し順

投稿 September 18, 2018

ホームボタン(〇ボタン)を押すと、アプリは中断され、ホーム画面に戻ります。

アプリ中断時のメッセージ送信順を記録しておきます。 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 関数に相当すると思われます。
私は特に何もしていません。

▲ページ先頭へ

アプリ再開時の呼び出し順

投稿 September 18, 2018

アプリを再開させたときののメッセージ送信順を記録しておきます。 Android のバージョン 4.4.2 での調査結果です。

APP_CMD_START

アプリ起動時と同じく、このメッセージが来ました。

APP_CMD_RESUME

アプリ起動時と同じく、このメッセージが来ました。

APP_CMD_INPUT_CHANGED

アプリ起動時には送信されるこのメッセージは、再開時には送信されてきていません。

APP_CMD_INIT_WINDOW

アプリ起動時と同じく、このメッセージが来ました。 破棄されたウィンドウを再度準備します。

APP_CMD_GAINED_FOCUS

アプリ起動時と同じく、このメッセージが来ました。

▲ページ先頭へ

アプリ終了時の呼び出し順

投稿 September 18, 2018

アプリがアクティブな状態から、いきない終了にすることはできないと思います。 いったん中断と同じようにメッセージを処理し、クリーンアップしておきます。

本当の終了時(使用したアプリ一覧から削除)するときには、ログ出力できるメッセージは何も来ていないようでした。 現在の(ファイルへの)ログ出力コードが、ウィンドウが終了するとログを出せなくなるため、見えないだけと思われます。

▲ページ先頭へ


関連トピックス

C/C++ によるログ出力
メッセージ受領順を調べるためにログファイル出力クラスを作成しました。


その他のおすすめ
おすすめ記事はありません。

JavaScriptが無効です
▲ページ先頭へ

© 2017-2018 StraightApps.com 無断転載を禁じます。No reproduction without permission.