Simplify ViewBinding in Android with ViewBindingPropertyDelegate 2.0
I’m excited to announce the release of ViewBindingPropertyDelegate 2.0, which introduces significant under-the-hood refactoring to enhance the library’s stability and performance. In this article, I’ll highlight the most important changes and explain how they improve the library’s functionality.
Brief Introduction
ViewBindingPropertyDelegate(VBPD) is a lightweight library designed to simplify the use of Android’s ViewBinding by:
- Managing the ViewBinding lifecycle and clearing references to prevent memory leaks.
- Eliminating the need to maintain nullable references to Views or ViewBindings.
- Creating ViewBindings lazily.
The library supports usage in various components, including Activities, Fragments, ViewGroups, and RecyclerView.ViewHolders.
class ProfileFragment : Fragment(R.layout.profile) {
private val profileBinding: ProfileBinding by viewBinding(ProfileBinding::bind)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// ProfileBinding instance will be created lazily on first access
profileBinding.name.text = ...
}
override fun onDestroyView() {
super.onDestroyView()
// profileBinding reference will be cleared after onDestroyView()
}
}
Changes in 2.0
Transition from Lifecycle to Component Callbacks
In previous versions (1.x), VBPD relied on Jetpack’s Lifecycle to detect when a View was being destroyed. This approach had a limitation: the Lifecycle callback methods could be invoked before Fragment.onDestroyView(), while the ViewBinding reference was still needed. To address this, VBPD postponed clearing the ViewBinding reference using an Android Handler after onDestroyView(), when the Fragment’s View LifecycleOwner transitioned to the DESTROYED state.
In version 2.0, VBPD now utilizes FragmentManager.FragmentLifecycleCallbacks to detect when a Fragment’s view is destroyed. The key difference lies in the timing of these callbacks, allowing for more precise management of the ViewBinding lifecycle.
// Source code from Jetpack Fragment 1.8.5
public class Fragment {
// Called by FragmentManager
void performDestroyView() {
...
if (mView != null &&
mViewLifecycleOwner.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.CREATED)) {
// Trigger the destruction of the Fragment's View LifecycleOwner
mViewLifecycleOwner.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
}
...
// Invoke Fragment's onDestroyView() callback
onDestroyView();
...
}
}
// Source code from Jetpack Fragment 1.8.5
class FragmentStateManager {
void destroyFragmentView() {
...
// Internally calls Fragment's performDestroyView()
mFragment.performDestroyView();
// Trigger FragmentLifecycleCallbacks
mDispatcher.dispatchOnFragmentViewDestroyed(mFragment, false);
...
}
}
This change resolves issues related to Fragment animations and eliminates the need for APIs that were previously required due to the behavior of Jetpack’s Lifecycle in Fragments.
Similarly, for Activities, VBPD has transitioned to using ActivityLifecycleCallbacks. For ViewGroups, the library does not depend on Lifecycle and is connected to the lifecycle of the ViewGroup instance in memory.
Removal of State Checks
In versions 1.x, VBPD enforced checks to ensure that access to the View occurred at the appropriate time, such as from the main thread between a Fragment’s onViewCreated() and onDestroyView(). While this was a sound decision, it caused confusion among users who did not clear references to Views within Fragments, as they only added and removed them using Fragment Transactions.
In version 2.0, VBPD no longer performs these state checks and instead relies on the behavior of the components themselves. This simplification allows users to manage their own errors until the Fragment or other component throws an exception.
Changes to Artifact ID and Base Package
Due to the significant internal changes, it’s essential to allow the coexistence of both the old and new versions of the library. Therefore, the artifact ID and base package names have been updated. You can migrate step by step or perform a global replacement in your IDE from com.github.kirich1409.viewbindingpropertydelegate
to dev.androidbroadcast.vbpd
. Don’t forget to add the dependency dev.androidbroadcast.vbpd:vbpd:2.X.Y
to your project.