Android 1.6のDate#toStringは重いので注意

あるメソッドの実行時にパラメタにセットしてあるモデルをダンプしようとトーストを使用した所、やたらと遅くなる。Androidのバージョンは1.6だ。

public void post(AttendantModel model) {
    Toast.makeText(activity, "ボタンが押下されました model = " + model.toString(), Toast.LENGTH_SHORT).show();
}

早速SDKのプロファイラ(TraceView)で調べて見ると、どうやらモデル中のフィールドで使用しているDateクラスのダンプ(toString)が遅いようだ(12回の呼び出しで13240msec)

どうしてこんなに掛かっているんだろう。

改めてAndroid1.6におけるDate#toStringを見てみた。

public String toString() {
    return new SimpleDateFormat("E MMM dd HH:mm:ss z ", Locale.US) //$NON-NLS-1$
            .format(this)
            + new GregorianCalendar(milliseconds).get(Calendar.YEAR);
}

なるほど、呼ばれる度にSimpleDateFormatでフォーマットしているが、このフォーマット処理が重いらしい。

更に深く降りていくと解るが、SimpleDateFormatの書式文字列の指定にタイムゾーン("z")を使用しており、そこから呼ばれるgetTimeZone()が原因のようだ。


JNIまで降りた上で遅いのであれば、現状はどうしようもない。Android 1.6のDate#toString(というか、getTimeZone)は要注意ということで、できるだけ使わないか使っても一度だけにすべきというのが結論か。

ちなみに、最新のソースではどうなっているのだろう。

public String toString() {
    Calendar cal = new GregorianCalendar(milliseconds);
    return dayOfWeekNames[cal.get(Calendar.DAY_OF_WEEK) - 1] + " " + monthNames[cal.get(Calendar.MONTH)]//$NON-NLS-1$
            + " " + toTwoDigits(cal.get(Calendar.DAY_OF_MONTH)) + " " + toTwoDigits(cal.get(Calendar.HOUR_OF_DAY))//$NON-NLS-1$ //$NON-NLS-2$
            + ":" + toTwoDigits(cal.get(Calendar.MINUTE)) + ":" + toTwoDigits(cal.get(Calendar.SECOND))//$NON-NLS-1$ //$NON-NLS-2$
            + " " + cal.getTimeZone().getID() + " " + cal.get(Calendar.YEAR);//$NON-NLS-1$ //$NON-NLS-2$
}

なるほど、SimpleDateFormat自体使うのを止めたらしい。事実、2.1で動かしてみるとtoStringが重かったのが嘘のように消えてしまっている。