[Android] DataBinding-ktx 3.0.1 Released

Takumi WADA
DataBinding-ktx
Published in
2 min readDec 7, 2019
DataBinidng-ktx 3.0.1: Fix memory leak when using binding in onDestroyView

What is DataBinding-ktx

A library that solves problems related to DataBinding and ViewBinding, and is safe and easy to use.

DataBinding / ViewBinding issues

1. Variable declaration method is different between Activity and Fragment

By lazy can be used in Activity , but when using BackStack or Attach / Detach in Fragment’s view is regenerated, so by lazy cannot be used (*).
*: Because binding instance is not generated for the view after regeneration

2. Forget to call setLifecycleOwner

This is only a problem with DataBinding. When using LiveData, LiveData will not be binding unless setLifecycleOwner is called.

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. Forget to call 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

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

About DataBinding-ktx 3.0.1

You can use binding safely in onDestroyView

binding is implemented internally as lazy. Since Fragment has regeneration of View, binding is set to null in onDestroyView. However, the actual setting timing was just before onDestroyView. When binding is used in onDestroyView, since the binding is null, it will be inflate again and the binding will not be set to null after that. (See below)

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

In DataBinding-ktx 3.0.1, the timing for setting binding to null was corrected immediately after onDestroyView. For this reason, using binding in onDestroyView does not inflate, and after onDestroyView the binding is null, so there is no memory leak.

Click here for DataBinding-ktx 3.0.1

--

--