見出し画像

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

DataBinding-ktx とは

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

DataBinding/ViewBinding に関する問題

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

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

 2. Fragment は onDestroyView で binding を null にしないとメモリを浪費する

Navigation component やバックスタック、デタッチを利用している場合、onDestroyView で Fragment の View は解放されるが Fragment が生きています。binding は View Tree を保持しているため解放しないとメモリを浪費してしまいます。

 3. setLifecycleOwner を呼び出し忘れる

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

DataBinding-ktx による解決

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

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

 2. Fragment は onDestroyView で binding を null にしないとメモリを浪費する

Delegated Properties 内部で View と同時に binding も解放されるためライブラリ利用者は意識する必要がありません。

 3. setLifecycleOwner を呼び出し忘れる

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

DataBinding-ktx の使い方

 DataBinding

private val binding: DataBindingActivityBinding by dataBinding()

 ViewBinding

private val binding by viewBinding { ViewBindingActivityBinding.bind(it) }

 Activity

binding 変数を使う前に setContentView を呼び出すか、レイアウト ID をコンストラクタに渡してください。

class DataBindingActivity : FragmentActivity() {
   // Declare the `binding` variable using `by dataBinding()`.
   private val binding: DataBindingActivityBinding by dataBinding()
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.data_binding_activity)
       // You can use binding
   }
}
class DataBindingActivity : AppCompatActivity(R.layout.data_binding_activity) {
   // Declare the `binding` variable using `by dataBinding()`.
   private val binding: DataBindingActivityBinding by dataBinding()
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       // You can use binding
   }
}

 Fragment

onCreateView で inflater.inflate を呼び出すか、レイアウト ID をコンストラクタに渡してください。

class DataBindingFragment : Fragment() {
   // Declare the `binding` variable using `by dataBinding()`.
   private val binding: DataBindingFragmentBinding by dataBinding()
   override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
       return inflater.inflate(R.layout.data_binding_fragment, container, false)
   }
   override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
       super.onViewCreated(view, savedInstanceState)
       // You can use binding
   }
}
class DataBindingFragment : Fragment(R.layout.data_binding_fragment) {
   // Declare the `binding` variable using `by dataBinding()`.
   private val binding: DataBindingFragmentBinding by dataBinding()
   // DO NOT override onCreateView
   override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
       super.onViewCreated(view, savedInstanceState)
       // You can use binding
   }
}

 備考

レイアウト ID をコンストラクタに渡し忘れた場合、Activity ではクラッシュし、Fragment では表示されません。そのため、以下のようなクラスを定義すれば良いと思います。

open class DataBindingAppCompatActivity<T : ViewDataBinding>(@LayoutRes contentLayoutId : Int) : AppCompatActivity(contentLayoutId) {
   protected val binding: T by dataBinding()
} 
class YourActivity : DataBindingAppCompatActivity<YourActivityBinding>(R.layout.your_activity) {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       // You can use binding
   }
}
open class DataBindingFragment<T : ViewDataBinding>(@LayoutRes contentLayoutId : Int) : Fragment(contentLayoutId) {
   protected val binding: T by dataBinding()
} 
class YourFragment : DataBindingFragment<YourFragmentBinding>(R.layout.your_fragment) {
   // DO NOT override onCreateView
   override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
       super.onViewCreated(view, savedInstanceState)
       // You can use binding
   }
}

ViewBinding は以下の通り。

open class ViewBindingAppCompatActivity<T : ViewBinding>(@LayoutRes contentLayoutId: Int, bind: (View) -> T) : AppCompatActivity(contentLayoutId) {
   protected val binding by viewBinding(bind)
}

class YourActivity : ViewBindingAppCompatActivity<YourActivityBinding>(R.layout.your_activity, YourActivityBinding::bind) {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       // You can use binding
   }
}
open class ViewBindingFragment<T : ViewBinding>(@LayoutRes contentLayoutId : Int, bind: (View) -> T) : Fragment(contentLayoutId) {
   protected val binding: T by viewBinding(bind)
} 
class YourFragment : ViewBindingFragment<YourFragmentBinding>(R.layout.your_fragment) {
   // DO NOT override onCreateView
   override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
       super.onViewCreated(view, savedInstanceState)
       // You can use binding
   }
}

DataBinding-ktx 4.0.0 はこちら


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