Android
Kotlin

FragmentでKotlinのby lazyを使ってfindViewByIdするとレイアウト反映できない&リークする件

More than 1 year has passed since last update.

何が起きる?

ちょっと昔のネタなのですが、時々忘れて使いそうになるので、簡単にメモしておきます。
Kotlinではviewへのアクセス時にfindViewByIdしてくれるように、こんな感じで遅延初期化して利用することができます。

private val toolbar by lazy {
    view!!.findViewById<Toolbar>(R.id.toolbar)
} 

ただlazyを使うと一度取得したものをメンバ変数として保持し、次に利用するときも同じインスタンスを返します

ここでFragmentのライフサイクルを思い出すと、以下のようにバックスタックから返ってきた時に、onCreateView()がまた呼ばれます

onCreateViewでレイアウトを新しく作って返すと、、メンバ変数で持っているViewは前に作ったレイアウトなので、リークします。また、textView.text = "hoge"などしてもレイアウトの見た目に反映されません

ではどうするべき?

ここにそれぞれの方法のメリデメがまとまっています。
https://discuss.kotlinlang.org/t/pros-cons-of-android-view-access-strategies/3160

  • 現状、lateinitが一般的っぽい?です
  • 一応、Kotlin Android Extensionでもちゃんとやってそうな雰囲気です。
  • Architecture ComponentのLifecycleOwnerとKotterKnifeを利用することができれば、以下のコードでできそうです。 https://gist.github.com/chrisbanes/fc4392dcbdc0aa5d99147dc551616676

元ネタ

https://twitter.com/chrisbanes/status/897075635142754305