titaniumで作ったアプリがメモリリークするときに行った対処法3つ

  • 21
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

カメラを起動してバーコードを撮影し、そこから読み取ったISBNコードを使ってAmazonAPIを叩いたり何だりするアプリを作ったものの、やたらと落ちる。
そんなときに行った対処法です。

HTTP通信

APIを叩くときなど使用頻度の高いHTTP通信ですが、Titanium.Network.HTTPClientを使ったときにメモリリークが多発。
原因:単純に通信後メモリ解放が出来ていない
解決:通信終了後にonloadなどのコールバックメソッドにnullを渡してあげる
ということで、以下のように実装しました。

var client =  Ti.Network.createHTTPClient({
  onload : function(e) {
  /* 
   * 無事レスポンスが返ってきたときの処理
   * ex) nextScreen関数に返ってきたテキストを渡す
   */
  nextScreen(this.responseText);

  /* nullを渡してコールバックメソッドの解放 */
  client.onreadystatechange = null;
  client.onload = null;
  /* HTTPClient自身にも */
  client = null;
 },
 onerror : function(e) {
  /* エラー時のステータス出力 */
  Ti.API.info('error: ' + e.source.status);

  /* nullを渡してコールバックメソッドの解放 */
  client.onreadystatechange = null;
  client.onerror = null;
  /* HTTPClient自身にも */
  client = null;
 },
 /* タイムアウト設定(1ミリ秒) */
 timeout: 1000
});

/* ついでにロード画面 */
client.onreadystatechange = function() {
 if (this.readyState == 2) {
  $.loadImage.backgroundImage = "/img/画像ファイル";
 }
};

参考
- Titaniumでネットワーク周りのメモリリークを回避する/M.P.B.

EventListener

次に取りかかったのがEventListenerの見直し。
イベントリスナーを追加した場合、イベント終了時にイベントを削除する必要があるとのこと。
原因:イベントがずっと生きている
解決:用の済んだイベントを削除
ダイアログを例にとると、このように実装しました。

var arr = ["first", "secont", "third"];
var dialog = Titanium.UI.createOptionDialog();
 /* ダイアログのタイトルとオプション(選択肢)をセット */
 dialog.setTitle('ダイアログタイトル');
 dialog.setOptions(arr);
 
 /* オプションが選択されたときの処理 */
 dialog.addEventListener('click', function(event) {
  number = event.index;
  /* イベントリスナーの削除 */
  dialog.removeEventListener("click", arguments.callee);
 });

参考
- Documentation Guides - Managing Memory and Finding Leaks

画面遷移

画面遷移というか、結果として画面遷移に関係する形で解決したもの。
原因:ISBN読み込む→必要な情報取得→画面遷移&表示 の流れが早過ぎて忙しくなった
解決:余計な処理を間に挟む
画面遷移時に0.5秒のインターバルを設けました。

function openAndClose(controller){
 /* 0.5秒経過したら次の画面に遷移し、今の画面を閉じる */
 setTimeout(function(){
  nextScreen.open();
  $.Screen.close();
 }, 500);
}

と、書いたもののfireEvent使えば余計な処理書かずに解決出来るらしいので、今度実装してみようかと思います。