「 Android 」一覧

Androidアプリのライフサイクル&再開処理


ネイティブコードでメインの処理を行うとして、Javaの部分は単にActivityという入れ物にしか使わない、という感じでアプリケーションを作成することを考えている。今のところOpenGLESをつかっていて、Android特有の問題に悩まされている。

  • 複雑なライフサイクルで、OpenGLのコンテキストが再生成されている
  • その再生成のタイミングで今まで使用していたリソースが無効状態となる
  • そもそもOpenGLなのに、DirectXのようなデバイスロストに似た症状が発生する

Androidの通常アプリのActivityは以下の図に示す遷移をたどる。この図はGoogleのAndroidのページにあるものと同じである。

調べてみたところ、ユーザーの操作によって、似たように見えていても違う遷移となる点も確認できた。

  • 起動後、ホームボタンを押す。その後もう1度起動させるケース
    • onCreate – onStart – onResume – (実行中) – onPause – onStop –  onRestart – onStart – onResume – (実行中)
  • 起動後、Backボタンを押す。
    • onCreate – onStart – onResume – (実行中) – onPause – onStop – onDestroy
  • 起動後、放置してスクリーンのタイムアウトなどでActivityが見えなくなる
    • onCreate – onStart – onResume – (実行中) – onPause – (スクリーン復帰) – onRestart – onStart – onResume – (実行中)
サンプルのアプリケーションでは surfaceCreatedあたりでシェーダーやテクスチャなどの初期化を行っている。これが上記のどの部分になるかを調べてみたところ、onResume の直後あたりになるようだ。そしてsurfaceChangedも同部分になるようだ。

一方で、surfaceDestroyedなる部分は、onPauseの後になる模様。onStopに遷移するタイミングで実行されるみたい。

このつくりだとアプリケーションが再び実行状態になる前には surfaceCreatedを通過するため毎回リソース生成が行われるので、問題なく画面描画ができることになる。リソースの破棄処理がどうなっているのか疑問は残るが。
たぶん、確実にリソース処理しようとすれば onPauseで一時解放しておくのがよく、surfaceCreatedのタイミングで再生成するのがいいんだろう。

さて、上記の遷移はあくまでJavaの部分でのActivityの各イベントハンドラで検知した感じの情報。
これを C/C++の部分でどうやろうか、というのが問題となってくる。従来までの作りをしているアプリケーションだと、最初に初期化して、アプリ内グローバルなインスタンスはアプリ最後まで生き残ることを想定している。このグローバルなインスタンスにはグラフィックスやサウンドの管理部分がいたりする。
書籍「Androidネイティブプログラミング」 にもある例だと、surfaceCreatedのタイミングで初期化を行い、onDrawFrameの部分でC/C++のメインループへ実行を飛ばしている。これの作りをそのままにしておくと、アプリの切り替えから復帰しようとした時には常に初期化処理から実行されることになる。2重初期化を検知してエラーとか出すような作りにしていれば、そこでエラーとなる。あるいは初期化から再スタートなので、先ほどまでのデータが残っていたりはしない。

さて、もう1度よく考えてみよう。

再初期化が必要なのはいったい何か。アプリケーションのデータは初期化してしまう必要はあるか?

そう。必要なのはデバイスにアクセスしているようなグラフィックスやサウンドの部分についてだけ。その他のアプリケーションがメモリに持っている各データ状態はそのままでいいはずである。画面遷移するまでに使っていたリソースを再度確保してあげるコードを用意して、ほかの状態から戻ってきたときにその部分を処理するようにすれば、理論上はそのアプリケーションは切り替え前の状態に戻るわけで問題なく再開が可能なはずだ。

では、リソースの解放や再確保の部分はどこで行うべきか。
個人的には次のように考えている。onPauseの部分でリソースの解放処理を行ってしまい、ほかのアプリケーションの邪魔をしないようにする。これにはリソースを減らしてあげることでAndroidシステムから真っ先に消される可能性を幾分か減らしてくれるはずだ。 そしてこのonPauseを通過したことを示すフラグを立てておく。
リソースの再確保の部分はどこに書くのか、実行するのか。これはonDrawFrameの中でやるか、surfaceCreatedあたりでやるかしか方法はなさそうである。理由はコンテキストの再生成が行われた後、ウィンドウが表示されていることなどその他の要因があるからである。どちらの部分にせよ、C/C++へのジャンプコードが入っているので、先ほど覚えておいたフラグを用いてonPauseを通過済みであるならリソースの再確保処理を行ってあげるコードを実行すればよいだろう。最後に忘れてはならない点は、このonPauseの通過フラグは onCreateのタイミングで確実にfalseを設定してあげること。

理由を説明すると、このフラグはおそらくグローバルに持つ感じになるだろう。Androidのシステムにおいてメモリイメージは再利用される可能性があるので、あるタイミングではこのフラグがtrueのまま最初から実行されレしまう可能性もある。一応onPause, onStopからonCreateへの遷移ではメモリ解放となっているが、onCreateでfalseにしてしまったほうが安全に思える。

まとめると、onPauseの部分で onLostDevice相当の関数を実装&実行させ、onResumeの後のsurfaceCreated/onDrawFrame内でonResetDevice相当の関数を実装&実行させれば、リソースの復帰が可能だろうと思われる。

AndroidのGLSurfaceViewが面倒を見てくれるのは、EGL,GLのコンテキストの再生成まで。それ以外のテクスチャやシェーダー、FBO,VBOなどは再生成を手動で行う必要がある。それはオールJavaで書いてあっても同様だ。


ANDROID_NDK_ROOTの設定について


どうも ANDROID_NDK_ROOT の設定に困る。
というのも、cygwin形式パスと、Windows形式パスと2種類それぞれ期待されている節があるからだ。

Windows形式を期待

VS-Androidは 環境変数 ANDROID_NDK_ROOT にWindows形式のパスを期待しているようだ.
仮にcygwin形式を設定しておくと、ビルドができなくなる。
正しい設定にしろ、見直せといってくる。

cygwin形式を期待

ndk-gdb は間違いなくcygwin形式を期待している。
ANDROID_NDK_ROOTをWindows形式で設定している場合、ndk-gdbを起動すると以下のようなメッセージが出てくる。

解決方法

ネイティブで書きたい人(自分とか)の場合、VisualStudioも使いたい、gdbも使いたいと欲張っていきたいです。
これら2点を解決する方法として、自分では以下の方法で対処しました。

  1. Windowsの環境変数 ANDROID_NDK_ROOTにはWindows形式で設定
    1. VisualStudio(VS-Android)で使うにはこのほうがいい
  2. cygwinの環境では、ホームディレクトリの .bashrc を編集
    1. このファイルの末尾に、以下のように記述して、環境変数を上書きにします。

おまけ

いくつかの設定方法を試していたりすると、
今までに説明した症状に出会わないかもしれません。
それはきっとその作業の中で上記で説明した対処法にたどり着いている可能性があると思います。
(意識しないでうまくいっている環境に出会ってしまったので)


Android SDK r14以降でVS-Androidを使う


Android SDK r14(Android 4.0をサポートしたバージョン)から、VS-Androidのサンプルですらビルドが通らなくなった。VS-Androidのサンプルのチュートリアル通りにやってみても失敗し、次に示すエラーメッセージが表示される。 

そもそもVS-Androidを入れての開発環境ではbuild.xmlはサンプルからコピーして使っていたし、これはそもそも自動生成してできるものじゃなかった。

調査結果

このエラーメッセージはそもそもどこで出されているのかを調べてみた。
r14の状態では、このメッセージは tools/ant/pre_setup.xml に記載されていた。
従来までなら、ここに処理(&設定)が書かれていたはず。

VS-Androidのサンプルにあった build.xmlではこのpre_setup.xmlをインポートして使っていた。
SDKを更新したことで、この役割が変わったようだ。
pre_setup.xmlと同じ場所に、build.xmlというxmlが存在するようになったみたいだ。

解決方法

以下の手順で従来の build.xmlを最新の環境で使用できるようになる。

1.buld.xmlの次の行を編集

この部分を、次のように変更する.

2.となっている行を削除

サンプル

自分の環境で “testProj”というVCProjを作成した際に使ったbuild.xmlを下記に表示します。
NativeActivity, hello-JNIのサンプルでこのbuild.xmlが使えることは確認しています。
(ただし、project name=”***”の部分は適宜変更してください)


Android 4.0 (ADT)での罠


Android 4.0が出て、SDKをインストール&更新していたら、
eclipseでうまく動かなくなった。
新規のAndroidプロジェクトを作成しようとしたら、ターゲットSDKのバージョンを選べず真っ白だったりとか。
そんな状態だったので、ADTを更新したらさらに悪化した。。。。Android SDKのパスがリセットされたのかと思ったけど、そういうわけでもなさそう。
ただ設定項目を開くと、以下のようなメッセージが表示されている。

“com.android.sdkuilib.internal.widgets.SdkTargetSelector.access$000(Lcom/android/sdkuilib/internal/widgets/SdkTargetSelector;)Z”

どうやってもわからなかったので調べてみたところ、
eclipseの設定を一度リセットして再度プラグインを読み込ませる方法でいいらしい。

eclipseのあるフォルダには eclipse-clean.cmd があると思うので、
このエラーが発生したときにはこのバッチファイルを実行してeclipseを起動すればよい。
こちらではこの方法でうまく解決できた。

その他

ちなみにAndroid SDKを最新(4.0を含んだやつ)に更新したら、vs-androidのほうで失敗するようになった。
こちらをこれから調べてみようと思う。


ネイティブAndroid開発に期待が?!


VisualStudioのアドインとしてのVS-Androidを探している途中に、たまたま見つけた”VS-Android-Debugger”というもの。
名前から、VisualStudio上でAndroidのデバッグができるようになるに違いないと期待しています。vs-android-debugger

普段の開発でVS-Androidとこのデバッガーと両方そろえば、cygwinやeclipseからオサラバできそうな感じです。

今のところ発足したばかりのようで、今後に期待ですね。


WinGDBがイケてる


Androidのネイティブプログラミングをしているときに厄介なのがデバッグ作業です。
一応、最近のSDK(NDK)を使っていれば、ndk-gdb でデバッガをつなげたりするのですが、ちょっと大変です。
できることなら普段のVisualStudioで開発するような感じで実行&ブレークポイント設定したいもんです。これを実現させてくれるのが、WinGDB for Mobile Systems というソフトウェアです。
現在はまだベータ版なのですが一通りのことは実現させてくれます。
今から製品版が楽しみで、登場したら価格次第ではさっさと買いたいですね。

Java + jniで構成されている環境をインポートして.slnを作成します。
あとは、いつもどおりにF5で実行が可能です。

できたこと

  • ソースコードレベルでのブレークポイント設置
  • 変数の値表示、メモリ表示

不満点

  • スタティックライブラリ作成

ゼロからのプロジェクト作成で、ネイティブのスタティックライブラリを作成することができないという点です。
個人的にちょっとこれは対応してほしい点ですね。
Android.mkなどがすでに用意されている状態でならば、インポートによりスタティックライブラリの開発ができました。

  • Tegra Android Development Pack(TADP)との相性

どうもTADPをインストールした後でWinGDBいれるとうまく動かないようです。
cygwinやSDK,NDKのパスをTADPで設定されたものにしているのですが。
プロジェクトのビルドができないようです。

使う場合には、TADPに頼らずちくちくと自前でインストールしましょうってことなんでしょう。

まとめ

ndk-gdbがうまく使える環境なら、WinGDBも使えると思います。
手元ではGalaxySはうまく動きませんでしたが、ICONIA Tabでやってみたらうまくいきました。

ndk-gdbも、デバッガがない状態からすればとても便利なのですが、
このWinGDBからみるとやはり使いづらいと思います。
printfなどでデバッグしてきた世代からみると夢のような状態ですが、
ソースコードレベルでのデバッグしか経験してないと、Androidでネイティブの環境はきつすぎます・・・。


Tegra Android Development Packを入れてみた


ちょっと気が向いてしまったので、
AndroidのNDKも視野に入れた環境を試してみました。
先月あたりにはAndroid SDKいれてJavaでアプリ作成ということはやってみたのですが、
cygwinの面倒さやAndroidでわざわざC++使わなくてもということで、
NDKの部分においては触らないようにしていました。がしかし、Tegra Android Development Packの最新版が出ていたようなので、気が向いたこともありちょっと試してみました。

一応、NDKの環境を素からセットアップしたこともあるので
手間な部分については知っています。
それと比較すると、はるかにこのTegra Android Development Packを使ったセットアップは楽でした。
これからAndroidをNDK込みで始めたい!という人にはこれはオススメできます。
環境変数などの設定はインストーラーが勝手にやってしまうので、
そこの部分を自分仕様にしたい人には向かなそうですが。

また、cygwinのbinらにもパスが通ってしまうので、
このあたりを嫌う人にはちょっと難しいかもしれません。

手元にあったGalaxySでビルドして動作を確認してみたのですが、
一応動くようで、今のところ完全にTegra用というわけでもなさそうです。
ネイティブデバッガはまだ含まれていませんでしたし。
ネイティブデバッガが使えるようなバージョンになったころには、そのデバッガはTegra用という感じになるのだろうと思います。