2015年12月31日木曜日

タスクキラーを見切れ!の巻

今回も Android アプリにおけるメモリリークだとかアクティビティーのライフサイクルだとか、そういう話です。 「アタックダンジョンMMF」は12月10日リリース予定でしたが、案の定のびのびとなっています。

先に結論を書いて、そのあとに解説していくというスタイルで今回はいきたいと思います。 まずは、これから。 これは開発途中で棚上げしたマイアプリなんですが、単一のアクティビティーで作られている単純な代物です。 で、右上に 3 という数字が見えます。 これは、3回転したという意味なので、アプリを少しばかり稼働させたという証明です。 で、これを中断から再開します。 中断・再開の間に10時間以上は経過しており、その間にスマホのブラウザでインターネットを50分くらいしています。 つまり、デバイスに負荷を与えてからの再開です。

で、どうなるか。 開いてみたら右上のカウンターが 0 になっています。 これは、初期状態であることを意味します。 中断した後にすぐ再開した場合は、カウンターの値を引き継ぐのですが、今回はデバイス(Android の OS)のメモリ管理でキルされたみたいです。

はい、この単一アクティビティーアプリと同時刻にスタートして中断した別のアプリがあります。 こちらのアプリは3つのアクティビティーを持っており、わざと初期立ち上げのアクティビティー(メインアクティビティー)以外のソレで中断しています。 条件は先ほどと同じです。 中断・再開の間に10時間以上は経過しており、その間にスマホのブラウザでインターネットを50分くらいしています。 改造前は、これで開くとエラーが起きて強制終了でした。 OS のタスクキラーで初期化されているので、参照する変数が null になっていてバグが発生します。 しかし、気を付けて欲しいのは中断時に launching じゃない Activity が前面に出ている場合に限ってこういう事態になるということです。 確かにさっきの単一アクティビティーのアプリでは再開時に何事もなかったかのように初期化されており、 エラーは発生しませんでした。

このエラーってやつが発生するとユーザー様は怒り絶頂になるので、エラーは根こそぎ解決してからリリースしたいとマジで今回は思っています。 結局のところ、メモリの都合上、それなりの時間が経過するとアプリは初期化されるようです。 で、今回仕込んだ解決策は、これを根本的に解決するというものではなく、 (中断再開時に null になった場合はアプリ側の処理で初期化してスタートするだけのこと) ―――エラーが発生するかどうかって違いしかありません。 しかし、こうやってエラーを蛇蝎(だかつ)のように嫌い、斬って斬って斬りまくる姿勢を徹底することは素晴らしい…ハズ。 ユーザー様からの評価を、三次元的広角領域から得られるものだと確信しております。

moveTaskToBack(boolean nonRoot) という処理を行い、 OS側でアプリをデストロイしてもらうようにしました。 もちろん、デバイスがメモリ不足になった場合のお話ですけどね。 破壊を適正に行うためにバックグラウンドで待機する仕様みたいです。 つまり、仮死状態で待ちながら本体であるアンドロイドOSさんが 「なんかメモリのやりくりきつくなってきたんですけど」ということになれば、自らを破壊することで端末の負担を軽くするみたいですね。

仕組みとしては、イリーガルな中断の場合に必ずメインアクティビティーにバックさせるようにしています。 で、メインの onResume() で、他のアクティビティーから数値を初期化せずに戻ってきたかを判別して、 初期化されていなかった場合は moveTaskToBack(boolean nonRoot) という処理を行います。 しかし問題があった。なぜかゲームの流れでメイン→マップ→バトル→メイン→マップというアクティビティー遷移のサイクルを行うと、 突然アプリが終了してしまうという不具合が発生してしまう。 これの解決は、moveTaskToBack(boolean nonRoot) という処理を行う際にわざと0.5秒の待機時間を 発生させることで解決できました。 これは、なぜそうなるのか? には踏み込まず、対処療法でまあいいかと華麗にスルーしていきたいところです。

ちなみに、中断してすぐ再開した場合はフツーに中断地点からの再開となります。 BGMだけは頭に戻りますが、その他の状況は中断したときと同じです。 変数の初期化を onCreate() onResume() onStart() などで行わないようにすれば、これは可能です。 スマホなんで、どうしてもプレイしている状況が多岐にわたります。 家でガッツリとマジでやっている可能性は低いので、 職場の休憩時間でやっていて「ちょっとおお!」と呼ばれてゴニョゴニョしないといけない様な不安定なシチュエーションを想定するしかありません。

余談ですが、マシンの性能は日々向上しているのだから、メモリ不足はスペック改善によって解決されるのではないかね? と考えたいのですが、 実際は Android5.0 以降で新機能を実装したが故にメモリ関係のクラッシュを連発したりするようで…やれやれです。 Windows7 より後発の Windows8 が無駄機能がゴテゴテしすぎて遅いやないか、とユーザーから不評だったのと似ています。 やはり人間は業の深い生き物です。 それが現状なので、アプリ作成者は「いつ何時、どんな風にでも」終了できるようにアプリを設計すべきなのでしょうね。

終了といえば今年も終わりです。 「アタックダンジョンMMF」は12月10日リリース予定でしたが、その辺までは割と真面目に作業に励んでおりました。 逆に12月10日以降はほとんど手を付けなくなって本日に至ります。端的に申してやる気の問題です。 来年になったら頑張ろう。