AndroidのNavigationのnavArgsが便利そう。
Android + kotlin
最近、仕事で使っている Navigation Architecture Componentのバージョンを 1.0.0-alpha07から一気に2.0.0まで上げました。
そのときに、リリースノートを見ていたときに by navArgs()
というものを知ったのでメモ
これによって、例えば以下のように書いていたものが
val args = HogeFragmentArgs.fromBundle(arguments!!)
のようにfromBundleを噛ませて書いていたのが、Fragmentのクラスのメンバ変数として
private val args: HogeFragment by navArgs()
のようにかけることを知りました。
これを使うためには1.0.0-alpha10
以上の-ktx
のnavigation architecture componentが必要になります。
これによってメンバ変数として定義し、初期化を使用時に遅らせることができます。
従来でもメンバ変数として定義し、初期化を遅らせることはlateinitを使えばできたのですが、それがより簡単にできるようになりました。
蛇足
さてさて、navArgs()とはなんじゃろなとなったので、Android Studioで実装に飛ぶと
- FragmentNavArgsLazy.kt
@MainThread inline fun <reified Args : NavArgs> Fragment.navArgs() = NavArgsLazy(Args::class) { arguments ?: throw IllegalStateException("Fragment $this has null arguments") }
のような実装がされています。ここはkotlinの拡張関数を使って、NavArgsLazyを呼び出しているので、更に実装を見てみると
- NavArgsLazy.kt
class NavArgsLazy<Args : NavArgs>( private val navArgsClass: KClass<Args>, private val argumentProducer: () -> Bundle ) : Lazy<Args> { private var cached: Args? = null override val value: Args get() { var args = cached if (args == null) { val arguments = argumentProducer() val method: Method = methodMap[navArgsClass] ?: navArgsClass.java.getMethod("fromBundle", *methodSignature).also { method -> // Save a reference to the method methodMap[navArgsClass] = method } @Suppress("UNCHECKED_CAST") args = method.invoke(null, arguments) as Args cached = args } return args } override fun isInitialized() = cached != null }
のような記述が見えることになります。
このクラスが評価されるとget()
が呼び出され、キャッシュを持っている場合はキャッシュを返し、
初回呼び出し時には、argumentProducer
を使ってFragmentのargumentsが渡されているので、argumentsを型変数Argsに変換して返されることになるようです。
#
- リリースノート定期的に見よう。
- これ調べてたら
by
が何やってるのか気になったので動作を調べてみたい - バージョンを上げたら
arguments
がNullableを返すようになっていてfromBundle
がNonNullを受け取るので変更が面倒だった。。 - 上のソースコードのリンクのURLを貼りたいがどこかよくわかっておらず。。(汗)