見出し画像

[Android] DataBinding-ktx 3.0.1 をリリースしました

追記: DataBinding-ktx 4.0.0 をリリースしました

・・・

DataBinding-ktx とは

DataBinding と ViewBinding に関する問題を解決し、安全・簡単に利用するためのライブラリです。

DataBinding/ViewBinding に関する問題

 1. Activity と Fragment で変数宣言の方法が異なる

Activity では by lazy を使えますが、
Fragment では BackStack や Attach/Detach を使う場合は View が再生成されるので by lazy が使えません(*)。
※: 再生成後の View に対して binding インスタンスが生成されないため

 2. setLifecycleOwner を呼び出し忘れる

DataBinding のみの問題ですが、LiveData を利用している場合、setLifecycleOwner を呼び出さないと LiveData が DataBinding されません。

DataBinding-ktx による解決

 1. Activity と Fragment で変数宣言の方法が異なる

Kotlin の Delegated Properties によって ActivityFragment で同じ書き方でプロパティを宣言することができます。

 2. setLifecycleOwner を呼び出し忘れる

binding 変数に初回アクセス時に自動的に setLifecycleOwner が呼び出されているため呼び出し忘れがなくなります。

DataBinding-ktx の使い方

DataBinding

Activity

class MainActivity : AppCompatActivity() {
    private val binding: MainActivityBinding by dataBinding(R.layout.main_activity)
}

Fragment

class MainFragment : Fragment() {
    private val binding: MainFragmentBinding by dataBinding(R.layout.main_fragment)
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return binding.root
    }
}

ViewBinding

Activity

class MainActivity : AppCompatActivity() {
    private val binding: MainActivityBinding by viewBinding()
}

Fragment

class MainFragment : Fragment() {
    private val binding: MainFragmentBinding by viewBinding()
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return binding.root
    }
}

DataBinding-ktx 3.0.1 について

onDestroyView で binding を安全に使用可能

binding は内部的に lazy で実装されています。Fragment は View の再生成があるため、onDestroyView で binding に null を設定しています。しかし、 実際の設定タイミングは onDestroyView の直前でした。onDestroyView で binding を使用した場合、binding が null になっているので再度 inflate されて binding がその後 null に設定されることがないためメモリリークします。(下記参照)

fun <T : ViewDataBinding> Fragment.dataBinding(@LayoutRes layoutResId: Int): Lazy<T> {
   return object : Lazy<T> {
       private var binding: T? = null
       override fun isInitialized(): Boolean = binding != null
       override val value: T
           get() = binding ?: inflate<T>(this@dataBinding, layoutResId).also {
               binding = it
               viewLifecycleOwner.lifecycle.addObserver(object : LifecycleObserver {
                   @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
                   fun onDestroyView() {
                       viewLifecycleOwner.lifecycle.removeObserver(this)
                       binding = null // Called before onDestroyView!
                   }
               })
           }
   }
}

DataBinding-ktx 3.0.1 では、binding に null を設定するタイミングを onDestroyView の直後に修正しました。そのため、onDestroyView で binding を使用しても inflate されず、onDestroyView 後は binding が null になるため、メモリリークしなくなりました。

DataBinding-ktx 3.0.1 はこちら

ここから先は

0字

¥ 100

この記事が気に入ったらサポートをしてみませんか?