高畑 匡秀

2015.12.11

SharedPreferenceを使って学ぶkotlin

Kotlin Advent Calendar 2015の11日目の記事です
昨日は red_fat_daruma さんによるJavaからの利用を視野に入れたKotlinコードで何をするべきかでした
久しぶりのブログ更新です。最近Androidをあまり触らずiOSに浮気をしています。
浮気をしてる最中なので正直何を書こうか悩みました。kotlinでアプリを作るとか。spring bootをkotlinで…とか色々考えましたが、どれもあまりkotlinらしい内容にできそうになかったので
なるべくkotlin特有のものを…と必死に考えた結果SharedPreferenceを使って拡張関数や拡張プロパティ、DelegateについてAndroidで実際に使えるであろう場面について書こうと思います。

拡張関数

一言で言うと、既存のクラスにメソッドを独自に拡張できます。

例えばMutableListクラスにswapメソッドを拡張して、引数で受け取ったindexの値を入れ替えるメソッドを作ります

公式より

これだけでもちょっと便利だなぁという感じがしますが
もう少し実用的なやつで、AndroidのSharedPreferenceを拡張してみます。
多くの開発者がやるであろう、ObjectをJSON文字列にしてSharedPreferenceに保存するアレを拡張関数で定義してみます。
JSONのparserにはGSONを使っています。

この拡張関数を実際に使ってみます。

すごく使い勝手が良いんじゃないでしょうか?
これと同じことをJavaでやろうとすると、色々なところにGsonのシリアライズとデシリアライズのコードが出てきてしまったり、SharedPreferenceを継承したクラスを新たに作ったり、
はたまたSharedPreferenceのサービスクラスのようなものを実装しないといけません。
そして多くの場合ContextやActivityを引数として要求されて、嫌な気分になるのではないでしょうか?

拡張プロパティ

kotlinは関数だけでなくプロパティも拡張できます[公式より]

kotlinは標準でListにlastIndexというプロパティを拡張しています。

Listの終端を参照するのに毎回(size-1)をするより明示的でいいですね

これを参考にActivityにSharedPreferenceを返すプロパティを拡張してみます
返り値(Activity.(String) -> SharedPreferences)がちょっと複雑な形していますが、これはStringを引数として受け取ってSharedPreferencesを返す関数リテラルが返り値となっています。

実際に使うと

とりあえずSharedPreference返すプロパティを作りました。getSharedPreferenceを呼ばなくもSharedPreferenceを取得できるようになりました。
ただこれに関しはもう普通にgetSharedPreferenceを呼ぶでいいと思います…

Delegate

続いてDelegateです。こちらに関してはアドベントカレンダーの二日目に投稿されていた記事が参考になりますみんな大好きKotlinのDelegationについて #ktac2015
kotlinでAndroidをやるからには固く実装するために、変数は可能な限りvalにしたいものです。
しかしなかなかAndroidはそれを許してくれません。

そういうときに役に立つのがDelegateによる遅延初期化の機能です。

例えば標準で用意されているDelegates.NotNull()
これは以下のように実装されています

みての通りgetvalueが呼ばれたタイミング(プロパティにアクセスしたタイミング)でvalueがnullの場合はExceptionを投げるという実装です。
これを参考に自分でもひとつDelegateを作ってみます。
ジェネリクスを<T : Any>から<T : Activity>に変えて
getValueのところをExceptionを投げるというものからSharedPreferenceのインスタンスを作成するようにカスタマイズすればできそうです。

この自作したDelegateを使ってみると

固い!

しかし残念ながらこれだけではActivityではSharedPreferenceをbindできますが
Fragment上ではまだできません。なのでFragmentでも使えるように上記の内容を踏まえてごりごりに拡張していきます。

頭がパニックになりそうですが、このファイルを用意するだけで
SharedPreferenceのJSONの拡張関数を利用することでき
Fragment,Activityで、Delegateでバインドすることができるようになります。

ここまで読んでいただけるなんとなく気づくであろうと思われすがこれらは基本
kotterknifeの実装を真似ています。
Androidでkotlinを使うとお世話になる方も多いのではないでしょうか?

kotterknifeも中身はButterKnife.ktというファイルにActivityやFragmentの拡張関数や拡張プロパティ、Delegateクラスを用意しているだけです。
ただ用意しているだけとは言いましたが、kotlin初心者では中々解読できない代物でした…
なのでSharedPreferenceを使って真似て実装してみたのが今回のブログになります。

最後に

iOSに浮気していますが、kotlinをある程度勉強しているおかげでswiftがすごく読みやすいです。(たまにvar,val,letのパニック障害を起こしますが)
XCodeのサポートも多少の不満はあるものの、ほぼ問題ないレベルで補完が効くので開発しててストレスはあまり感じません。
AndroidとiOSの開発で言語の壁が大きかったのですが、swift,kotlinのどちらかを書ければ両方対応できる
そんな日も近いのではないでしょうか?
まだ趣味でしかkotlin書いてないので機会があれば次のプロダクトはkotlinでやりたいなぁ|ω・`)チラ