かなり手間をかけた全面刷新

コジごみカレンダー自体は 5 年近く前に初版をリリースした歴史ある Android アプリなのだが、アプリの構造が Android 2.2 時代のもののままなので更新するにも何かと制約がありモチベーションが保てなくなっていた。 なので現代の技術で全面リプレースするという構想は実は 2, 3 年前から持っていたのだが、既にかなり複雑なアプリに仕上がってしまっていたので移植しようとすると全ての機能を網羅しなければならず、なかなか最後まで続かない結果になっていた。 作っては中断、作ってはまた中断を繰り返しており、開発は頓挫状態となっていた。

Kotlin に感謝

では何故今回モチベーションが保てたのかというと間違いなく Kotlin のお陰だ。 既存の冗長な Java コードを Kotlin で書き換えるのが非常に気持ちよく、地味な移植作業を続けるのがそれ程苦ではなくなっていた。

今回 In-app Billing の既存のコード以外全て Kotlin で書き直している。 業務で Kotlin を使うのは流石に憚られたが、自分のアプリなら自由に使えるのでなかなか楽しい。

ただ 「Android 開発経験がそれほどない技術者は素直に Java で書いたほうがいい」と思った。 所々 Kotlin の文法ミスなのか Android SDK の API の使用方法が間違っているのか判断がつかない場面があったので、恐らく経験が浅いと解決できないのではないかと思われたからだ。

これが特に良かったという点

実際にコジごみカレンダーのコードを一部引用し述べる。

Fragment で Activity のインスタンスを使用する場合コンストラクタ等で行おうとするとまだ Activity に attach() されてないので getActivity()null になる。 これを避ける為には Fragment#onAttach() で Activity のインスタンスを参照するか Fragment#onActivityCreated()getActivity() するのが普通なのだが、そうすると以下のように退屈な代入を書かなければならない:

private ContentResolver mResolver;  // ここで代入できないから final にできない!!
...
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    mResolver = getActivity().getContentResolver();
}

Kotlin なら by lazy { ... } を使えば実際に使用する箇所でコードブロックが走る (遅延実行) ので大丈夫だ:

// mResolver を onActivityCreated() 以降でしか参照しないならこれで問題ない
private val mResolver: ContentResolver by lazy { activity.contentResolver }

多数の分岐を持った変数代入を Java でやると以下だ:

// 読みやすいけど退屈
final int backgroundColor;
if (year == currentYear && month == currentMonth && date == currentDate) {
    backgroundColor = getResources().getColor(R.color.calendar_today);
} else if (targetMonth != month) {
    backgroundColor = getResources().getColor(R.color.super_light_gray);
} else if (j == 0 || dayType.isHoliday(cal) || dayType.isExtra(cal)) {
    backgroundColor = getResources().getColor(R.color.calendar_sunday);
} else if (j == 6) {
    backgroundColor = getResources().getColor(R.color.calendar_saturday);
} else {
    backgroundColor = Color.WHITE;
}
columnLayout.setBackgroundColor(backgroundColor);

Kotlin だと when 文があるのでかなり簡潔になる:

columnLayout.setBackgroundColor(when {
    year == currentYear && month == currentMonth && date == currentDate -> resources.getColor(R.color.calendar_today)
    targetMonth != month -> resources.getColor(R.color.calendar_not_target_month)
    j == 0 || Utils.isHoliday(cal) || Utils.isExtra(cal) -> resources.getColor(R.color.calendar_sunday)
    j == 6 -> resources.getColor(R.color.calendar_saturday)
    else -> Color.WHITE
})

後は拡張メソッド (エクステンション) やトップレベル関数、インライン関数やラムダ式なども勿論便利だった。 もうプライベートで行うコーディングは Java で行う気がしない。