2017年05月30日

「Androidを支える技術U」を読んで その3

3.Androidのライフサイクルの役目

 前回書きましたように、頻繁に起きるメモリ不足によってkillされた多数のActivityが、ユーザーから見て、同時に多数動いているようにみせかける仕組みが「Activityのライフサイクル」という風に、私なりに解釈しました。

 著者の言葉で言うと、Androidが裏に行ったプロセスをkillしたり、それを再作成したりすることをそれほど意識せずに、まるでずっとアプリが立ち上がり続けているかのように開発ができるといのがライフサイクルの考え方です。

 しかし、著者も最後に書かれているように、一度でもアプリを開発した経験がある方であれば、「(実現はそう甘くありませんが)」ではあります(^_^;)何度悩んだことか(T_T)

 以下、著作は、ライフサイクルのもたらすものをユーザー視点と開発者視点から見ています。

(1) ユーザー視点から実現したいこと。

 ユーザーは無制限にアプリを起動して使っていく、そしてシステムが勝手に最近使っていないアプリを終了していき、しかしユーザーがそのアプリにまたやってくると前の状態を復旧する、これが通常のAndroidの想定された使い方です。 このように振る舞うことで ユーザーの端末のメモリリソースを最大限活用して様々なタスクの間を移動したときのレスポンスを機敏なものに保ちつつ、メモリが必要なタスクが動く時にはその分のメモリを自動的にあけようとします。

(2) アプリ開発者の視点から実現したいこと。

 いつ終了されても自動的に再開するコードを書くのは大変です。そこで、開発者が「一定の約束」に従ってコードを書けば、アプリの開発者は自分のプロセスが kill されて再開するときも、killされずにメモリ上にあったままの場合でも対応できるようにしたい。この「一定の約束」が「Activityのライフサイクル」です。

 そこで、開発者に対して具体的に求められるのは、裏に入ったActivityはkillされることがあるというよりは基本的にはkillされるものとして実装しておき、けれどキャッシュとして残っている場合にはそれを再生成する代わりに使い回していると考える方が実装者としては正しい見方となります。

 この結果として、このように裏に入ったActivityを キャッシュとして扱うことで、メモリが贅沢なマシンでは沢山の実体を残しておくことでたくさんのタスク間の移動を機敏に行える一方で、メモリが少ないマシンでも同じコードで自然とメモリを節約して複数タスクの切り替えのパフォーマンスは犠牲にしても、主要なタスクは問題なく動くというシステムを実現しているのが Android ということになります。

 いやー、改めてライフサイクルを意識してコードを書くことの重要性が再認識されます。

(3) Bundleの摩訶不思議

 最後に、ライフサイクルのひとつ、onSaveInstanceStateの中で利用される復旧情報を保存するためのBundleですが、著者は興味深い考察をされています。

 BundleはSystemServerのプロセスのメモリを使用するのでBundleにあまり大きなものを保存してはいけません。SystemServerのメモリが大きくなりすぎるとメモリを開けようとして裏のActivityをkillする頻度が上がるためタスクの切り替えがすごく遅くなったように感じますし、メモリー不足によるアプリの異常終了などが多くなってしまいます。

 しかし、

 Bundleは著者の知る限り ファイルには書き出されず、SystemServerのメモリ上に保持されたままです。個人的にはこれは信じがたいのですが、Bundleを保存してメモリを開放をしている箇所を見つけるべく相当長いことソースコードの中を探してもどうやっても該当箇所が見つけられませんでした。これではBundleにたくさんの値を入れるとSystemServerという 共有資源のメモリが圧迫されてOOMKillerが頻繁に発動するようになってしまう気がするのですが… だそうです。

 けれど、SystemServerはよほどのことがない限りkillされることはないそうですから、著者のおっしゃるように、ほどほどの大きさであれば、Bundleは安全に使えると理解し、ライフサイクルの基本にのっとって、onSaveInstanxeStateを利用していきたいと改めて思いました。

posted by 【なかま】 at 11:39 | Comment(0) | android
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: