プログラマってこんなかんじ??

アプリ作ったり歌ったりしてます

NativeDriver

Google謹製のテストフレームワークが!
Introducing Native Driver


サンプルではGoogleMapのテストが記載されとりますね。これはおもしろい。


Android Zaurusさんの日本語訳はこちら。
【超訳】AndroidのUIをUnitTestできるNative Driver


テストコード書くのは慣れないと書くのが大変、という点はあるけども、
テストを自動化できる、というメリットはやはりでかい。
さっそく試してみるとします。

ソース内の改定履歴

バージョン管理にコメントを残したとしても、ソースコードに改訂履歴のコメントを残す必要があるという主張 - プログラマとSEのあいだ


考えさせられた。


今の職場は svn 使用してます。
このあたりの意見は個人によってさまざま。
むしろコミットログ詳細を残す習慣がなく、
ソースコードに「担当者+日付+チケット番号+開始〜終了」みたいな人も多い。


いまの自分の考えはこうかなー。

  • できるだけ1回のコミットで、1つの課題(チケット)のみ対象とするようにする
  • 1回のコミットで複数の課題(チケット)が対象になる場合は、コミットログに修正詳細書いとく
  • ソース内に改定履歴は書かない


で、1課題で複数コミットが発生するような対応は

  • 基本的に branch で作業
  • 対応完了するまでは trunk にはコミットしない
  • 対応完了したら branch->trunk へマージ(1コミット)
  • マージ時に「branch -> trunkへマージ(r1:10)」みたいなコミットログ書いとく


という感じで作業していたりする。
trunk へのコミットはなるべく「1チケット1コミット」、
「branchでは好き放題コミット」みたいな。


gitとか分散型リポジトリだとまた話が変わってくるのかなー。
個人で使ったことはあるけども、複数人でgit使って作業したことがないからよくわからん。


うーん。どうするのが理想なんだろうか。

ADTのレイアウトエディタがすごい件

いつのまにか ADTのレイアウトエディタ が恐ろしく進化している!!


11(preview版)では xml を直接いじらなくても
エディタ上だけでこんなことができたりする。
(正確には 10.x でも動作する機能が一部あり)

  • 共通レイアウトの抽出
  • アニメーションのプレビュー
  • カスタムビューもD&Dで配置可能


eclipseのプラグイン自動更新では 10.x のバージョンまでしか落ちてこないが、
サイトには 11(preview版) がzipで配布されとります。(2011/5/30現在)


Android Tool Project Site


@yanzm さんがustで ADT11(preview版) について
説明してくれていたのだが、見てて衝撃を受けた。
(当日のログはハッシュタグ #debhw で検索したら見れるかも)


いままでADTのレイアウトエディタ(レイアウト用xml開いたら表示されるエディタ)は、
使い勝手が悪くてxmlを直接修正しないと使い物にならない、という意識だった。
どうせxmlいじらないとダメなんだからこんなエディタ使ってらんねー
と思って使うことすら避けてたのだけども。


いつのまにか超進化しとる。
ADTレイアウトエディタ派になってみる。

ダイアログの縦横切替でメモリリーク(XxxActivity has leaked〜)

AlertDialog.Builder#show〜 でダイアログ表示した状態で、
画面の縦横切替 を行うと例外発生してアプリ終了してしまった。


ログを見るとこんなエラーログが出力されている。

XxxActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@4053b7b0 that was originally added here


リーク発生!!


AndroidManifest.xml の 「android:configChanges」 属性をいじって
「Activityの再生成を行わないようにする」 が対応としては簡単なんだが、
これは根本的解決になっていないので却下。


ではどうしたものか、、というわけで調べてみると公式に記載発見。


Creating Dialogs


ダイアログ表示したいときは

「Activity#showDialog、onCreateDialog」を使ってねー
そうすると ダイアログのライフサイクル も Activity管理 になるよー

とのこと。


簡単に書くと、

  1. Activity#onCreateDialog を override してダイアログ実装しとく(任意idに紐付け)
  2. 任意の場所で Activity#showDialog(1で指定したid) を呼び出す
  3. onCreateDialog が呼び出されて ダイアログが表示される


そうすることで、
ダイアログ表示したままで Activityが再起動(onDestroy〜onCreate) したとしても、
Activityと一緒に自動的にダイアログも再表示される、と。
なるほど。


というわけでさっそく、
ボタン押下でダイアログを表示するだけのサンプルアプリ書いてみた。

public class MainActivity extends Activity {

    private static final int DIALOG_ID_ABESHI = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //case1 WindowLeaked発生するパターン(修正前)
        Button buttonLeak = new Button(this);
        buttonLeak.setText("leak");
        buttonLeak.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                Dialog dialog = createDialog(DIALOG_ID_ABESHI);
                if (dialog != null) {
                    dialog.show();
                }
            }
        });

        //case2 WindowLeaked発生しないパターン(修正後)
        Button buttonNotLeak = new Button(this);
        buttonNotLeak.setText("not leak");
        buttonNotLeak.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                showDialog(DIALOG_ID_ABESHI);
            }
        });

        LinearLayout layout = new LinearLayout(this);
        layout.addView(buttonLeak);
        layout.addView(buttonNotLeak);
        setContentView(layout);
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        return createDialog(id);
    }

    /**
     * ダイアログ生成
     * @param id
     * @return
     */
    private Dialog createDialog(int id) {
        if (id == DIALOG_ID_ABESHI) {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setMessage("あべし");
            builder.setPositiveButton("OK", new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    Log.d(getClass().getName(), "onClick");
                }
            });
            return builder.create();
        }
        return null;
    }
}


このコードで、ダイアログを表示したままで画面の縦横切替を行うとこんな結果になる。

case1 WindowLeaked〜 が発生する(ダイアログは勝手に閉じてそのままアプリ終了)
case2 ダイアログが表示された状態 で縦横画面表示


修正後の case2 だと、リーク発生しなくなった!!


そこでちょっと沸いた疑問。


もしかして、Activity#showDialog を呼ぶたびに onCreateDialog が毎回呼び出されて
毎回ダイアログ再生成、とかはないよなー??と。


Activity.java のソース見てみるとそんなことはもちろんなく、
一度生成済のダイアログは内部で保持されている様子。
よくできてる。


というわけで、ダイアログ表示する際には、
「Activity#showDialog、onCreateDialog」を使ったほうがいいね、というお話でした!

端末起動時に起動する常駐serviceのデバッグ(ACTION_BOOT_COMPLETED)

表題のような常駐serviceを作成しようとすると

BroadcastReceiver が intent(ACTION_BOOT_COMPLETED) を受けたらそれを契機にservice起動する

という仕組みが主流だと思う。(自分はこれしか知らない)

こんなserviceをeclipseで修正/動作確認しようとすると、

  • eclipseでソース修正->build->apkファイル作成
  • apkファイルuninstall
  • apkファイルinstall
  • emulator再起動

と非常にめんどくさい。
emulatorの再起動は時間がかかるのでなるべく控えたい。。


こんなときにー!


intentはコマンドラインでも投げれたりする。
たとえば、intent(ACTION_BOOT_COMPLETED)を投げる方法はこんなかんじ。

>adb shell
#am broadcast -a android.intent.action.BOOT_COMPLETED
  • eclipseでソース修正->build->apkファイル作成
  • apkファイルuninstall
  • apkファイルinstall
  • コマンドラインで intent(ACTION_BOOT_COMPLETED) 投げる
  • intent(BOOT_COMPLETE) を契機にservice起動

emulator再起動せずにこんなかんじで開発できるので便利便利。