sandbox

Scala, Android, Architecture, Management, Service Design あたりを主戦場としております

Activity がシステムによって kill される状態をシミュレートする方法

Android で、メモリが逼迫した状況下特有の不具合に遭遇し、そのデバッグ方法が分からなかったので調べてみた。
まず、メモリが逼迫した状態でどの様な事が起こるかというと、公式のドキュメントに下記の様な記載がある。

if the system must recover memory in an emergency, then onStop() and onDestroy() might not be called. Therefore, you should use onPause() to write crucial persistent data (such as user edits) to storage.


つまり、システムがどうしてもメモリを必要とする時には、既にスタックに詰まれている Activity が onStop や onDestory の呼び出しなしにプロセスが kill される事がある。
この状況を端末操作によって再現しようと思うとかなり困難だが、adb を使えばごく簡単に再現できた。(というか良く考えれば真っ当な手順)

  1. 対象の Activity を起動する
  2. Home ボタンで Activity を pause 状態にする
  3. adb kill の実行、または DDMS で対象のプロセスを選択し、STOP アイコンをクリックする


上記により、Activity が onDestory *1呼び出しなしに kill され、次回は onCreate から起動する流れをシミュレートできる。
一連の流れを logcat で見てみるとこんな感じ。

// 初回の起動
11-15 13:26:48.066: I/ActivityManager(278): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=me.tlync/.SampleActivity bnds=[186,543][294,688] }
11-15 13:26:48.166: I/ActivityManager(278): Start proc me.tlync for activity me.tlync/.SampleActivity: pid=14981 uid=10085 gids={}
11-15 13:26:48.266: D/SampleActivity(14981): [ENTER] onCreate
11-15 13:26:48.266: D/SampleActivity(14981): [ENTER] onStart
11-15 13:26:48.266: D/SampleActivity(14981): [ENTER] onResume

// Home ボタンで pause
11-15 13:26:58.016: I/ActivityManager(278): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10200000 cmp=com.android.launcher2/.Launcher }
11-15 13:26:58.136: D/SampleActivity(14981): [ENTER] onSaveInstanceState
11-15 13:26:58.136: D/SampleActivity(14981): [ENTER] onPause

// adb kill
11-15 13:27:03.556: I/WindowManager(278): WIN DEATH: Window{460a9978 me.tlync/me.tlync.SampleActivity paused=false}
11-15 13:27:03.556: I/ActivityManager(278): Process me.tlync (pid 14981) has died.
11-15 13:27:06.356: I/ActivityManager(278): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=me.tlync/.SampleActivity bnds=[186,543][294,688] }
11-15 13:27:06.416: I/ActivityManager(278): Start proc me.tlync for activity me.tlync/.SampleActivity: pid=15006 uid=10085 gids={}

// 再度の起動
11-15 13:27:06.516: D/SampleActivity(15006): [ENTER] onCreate
11-15 13:27:06.526: D/SampleActivity(15006): [ENTER] onStart
11-15 13:27:06.526: D/SampleActivity(15006): [ENTER] onRestoreInstanceState // 通常のライフサイクルでは呼ばれない onRestoreInsntanceState が呼ばれる
11-15 13:27:06.526: D/SampleActivity(15006): [ENTER] onResume


自身のケースでは単なる onCreate 時の不具合であったが、他にも何故かリリース後(他のアプリが頻繁に利用されメモリが逼迫されやすい状況)に Activity まわりで問題が発生するケースの再現や、普通に操作してもまず呼ぶ事ができない onRestoreInstanceState をテストしたい場合にも使える。

*1:"onStop() and onDestroy() might not be called" とあるが onStop は呼ばれた

PhoneGap で deviceready イベントが発行されない問題への対処

2011/11/15 追記: きっともう Obsolete


公式にあるサンプルでも deviceready が発行されないケースがあったので、対処方法をメモ。

公式にあるサンプルは下記の通り。

<!DOCTYPE html>
<html>
  <head>
    <title>PhoneGap Device Ready Example</title>

    <script type="text/javascript" charset="utf-8" src="phonegap.js"></script>
    <script type="text/javascript" charset="utf-8">
    document.addEventListener("deviceready", onDeviceReady, false);

    function onDeviceReady() {
        alert('なぜか呼ばれない');
    }
    </script>
  </head>
  <body>
  </body>
</html>


しかし、なぜか onDeviceReady が呼ばれない事がある。


結論から言うと、これは document.addEventListener が評価される時に、既に PhoneGap の初期化が完了しており、deviceready イベントが発行済みとなってしまっていた場合に起こる。
つまり、過去のイベントに対して addEvent してしまっている状況なので、当然といえば当然。


この問題には、下記の様に PhoneGap が初期化しているかどうかを判定する条件文を入れる事で対処できる。

<!DOCTYPE html>
<html>
  <head>
    <title>PhoneGap Device Ready Example</title>

    <script type="text/javascript" charset="utf-8" src="phonegap.js"></script>
    <script type="text/javascript" charset="utf-8">
    if(typeof device === 'undefined'){
        document.addEventListener("deviceready", onDeviceReady, false);
    }else{
        onDeviceReady();
    }

    function onDeviceReady() {
        alert('これは常に呼ばれるし、ちゃんと deviceready な状態');
    }
    </script>
  </head>
  <body>
  </body>
</html>

haml を html にリアルタイムパースする

素の html 書くのがしんどい & すぐに見つからなかったので node で書いてみた。
静的な html 書く機会が結構あるので便利。

※最初は hamljs 使って書いてみたけど、pre タグとか使いだすとまともにパース出来なかったので、結局 ruby haml を利用する様にしてみた。


usage:

node haml2html.js {target file} {ruby(default) or hamljs}
※同じディレクトリに同名の html ファイルが生成される。


Ubuntu で SandS を実現する最も簡単な方法

Linux で SandS を実現する方法はいくつかありますが、at-home-modifier を使えば、比較的簡単に設定できます。
http://gitorious.org/at-home-modifier


以下、手順のメモ。

ソースコードのダウンロード

git clone git://gitorious.org/at-home-modifier/at-home-modifier.git

ビルドに必要なライブラリをインストールする

sudo aptitude install autoconf xutils-dev xserver-xorg-dev libtool -y

configure & make install

cd at-home-modifier
./autogen.sh
./configure --prefix=/usr
make && sudo make install

設定

/usr/share/X11/xorg.conf.d/10-evdev.conf に下記を追記する。

  Section "InputClass"
    Identifier "my keyboard"
    Driver "evdev"
    Option "XKBOptions" "terminate:ctrl_alt_bksp" # and so on

    # If you save this file under xorg.conf.d/ :
    Option "AutoServerLayout" "on"

    MatchIsKeyboard "on"
    Option "TransMod" "65:50" # *** Look here ***
  EndSection

再起動すれば SandS が使える!


※ただし、Mac の keyremap4macbook の SandS と比較すると、若干反応が鈍くたまにスペースを認識しないのが難点。

4/9 DDD カンファレンスに参加してきました

先週土曜日、DevLove さんが主催する DDD カンファレンスに参加してきました。

DevLOVE Beautiful Development - ソフトウェアの核心にある複雑さに立ち向かう
http://kokucheese.com/event/index/9530/

ソフトウェア開発への取り組み方を改めて考えさせられる、とても有意義な素晴しいイベントでした。
もう既にまとめは皆さんに書いて頂いているので、遅ればせながら以下にかいつまんで感想を。

技術ではなくビジネスに焦点を


言葉にしてしまえば、当たり前の事だと思います。
システム開発において達成すべきはビジネス上の価値創造であって、どんな技術で実現したかは、ただの手段の話でしかないので。


しかし、"ビジネスに焦点を" というだけではなく、"ビジネスに焦点をあてたコードが書けていたか" という所まで自身に問いかけると、これは全然出来ていないなと。
例えば、陽の巻の渡邊さんが紹介されていた様なクソコードを、過去に自身も書いた事がある様な気がします…w


では、具体的にどの様なコードがビジネスに焦点をあてたコードと言えるのか、という点については、陽の巻の渡辺さんと、増田さんのセッションを見て、若干だけども理解出来たかなぁと。
あとはイベントでの講演者の皆さんの指南を礎としながら、DDD 本を手にとって理解を進めようかなと思ってます。


20110409_DevLOVE「ブレイクスルー体験記」_渡邉健太郎さん
http://www.youtube.com/watch?v=ovkG_sTYOKw


20110409_DevLOVE「実践! ドメイン駆動設計」_増田亨さん
http://www.youtube.com/watch?v=77BTZWq3GiQ

DDD でのモデリングとは


id:t-wada さんのセッションで、今回の様なイベント申し込みを例に、実際にモデリングしてみようぜというブートキャンプがありましたが、自身の経験としては効率性を重視した Transaction Script 的な設計が多かったのもあり、いざ設計してみようとなると、今までの考え方に引きずられ、最初にユースケース洗いだして、サービス層のロジック考えてという様な流れで考えてしまったり、ER 図の様な概念図を書きたくなってしまったりと、結局何をもって DDD でモデリングしたと言えるのか、DDD ではどの様なプロセスでモデリングを行うのか、という所がクリアでなく、悶々としたまま時間が過ぎ去りました。


未だ、上記の様なお題があった時に、どの様な手法でモデリングしていくのかはクリアになっていませんが、これは DDD 本読めという所でもあるかもしれないので、一旦書籍の到着を待ちたいと思います。


20110409_DevLOVE「DDDについて」_和田卓人さん
http://www.youtube.com/user/developlove#p/u/7/QMltFqbwhdw

まとめ


まず、震災後の複雑な状況の中、イベントを開催してくださった DevLove の皆さん、登壇者の皆さん、そして会場を提供下さった Oracle さんに感謝致します。


このイベントのお陰で DDD という考えを、皆さんのお話しを通じて知る事ができ、ソフトウェア設計、実装における考え方として深い示唆を与えて頂きました。


これから DDD 本を実際に読んで、更に理解を深めていきたいと思います。


※目標3人に DDD 本を買わせおすすめします。


エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

vimperator3 で TabNumber が正常に表示されない問題の対策

vimperator3 で set tabnumbers を指定すると何故かすべての番号が 1 になってしまう不具合??に遭遇。
とりあえず下記のコードを vimperatorrc に追記すれば番号は正常に振られる様になる。

style -name fix-tabnumbers chrome://* #TabsToolbar { counter-reset: tabnumber !important; }

原因は良く分からないけど、counter-reset が上手く効いていないのか。


before
f:id:tlync:20110406000736p:image

after
f:id:tlync:20110406000735p:image