[Android] DataBinding-ktx 4.0.0 Released

Takumi WADA
DataBinding-ktx
Published in
3 min readJan 22, 2020
DataBinding-ktx 4.0.0: Let’s use Activity/Fragment’s secondary constructor passing layout res id

What is DataBinding-ktx

It is a library for solving problems related to DataBinding and ViewBinding, and for safe and easy use.

Problems in DataBinding / ViewBinding

1. Variable declaration method differs between Activity and Fragment

Activity can use by lazy, but Fragment cannot use by lazy because there is View regeneration (*).
*: Because no binding instance is generated for the View after regeneration

2. Fragment wastes memory unless binding set to null in onDestroyView

When using the navigation component, back stack, and detach, Fragment’s view is released after onDestroyView, but the Fragment is still alive. The binding wastes memory if it is not released since it holds the View Tree.

3. Forget call to setLifecycleOwner

Only DataBinding is a problem, but if you are using LiveData, LiveData will not be binding unless you call setLifecycleOwner.

Solution with DataBinding-ktx

1. Variable declaration method is different between Activity and Fragment

Kotlin’s Delegated Properties allows you to declare properties in the same way in Activity and Fragment.

2. Fragment wastes memory unless binding set to null in onDestroyView

Because the binding is released at the same time as the View inside the Delegated Properties, the library user does not need to be aware of it.

3. Forget call to setLifecycleOwner

The setLifecycleOwner is automatically called when you first access the binding variable, so you will never forget to call it.

How to use DataBinding-ktx

DataBinding

private val binding: DataBindingActivityBinding by dataBinding ()

ViewBinding

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

Activity

Call setContentView before using the binding variable

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
}
}

or pass the layout ID to the constructor.

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

Call inflater.inflate in onCreateView

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
}
}

or pass the layout ID to the constructor.

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
}
}

Note

If you forget to pass the layout ID to the constructor, it will crash in Activity and will not appear in Fragment. Therefore, I think that you should define the following class.

DataBinding

Activity

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
}
}

Fragment

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

Activity

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
}
}

Fragment

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
}
}

Click here for DataBinding-ktx 4.0.0

--

--