How using ViewBinding with an abstract base class

Danny picture Danny · Jun 16, 2020 · Viewed 8.4k times · Source

I started using ViewBinding. After searching for some example or advice how to use ViewBinding with an abstract base class that should handle same logic on views expected to be present in every child's layout, I endet up posting this question here.

Scenario:
I have a base class public abstract class BaseFragment. There are multiple Fragments that extend this base class. These Fragments have common views that are handled from the base class implementation (with the "old" findViewById()). For example every fragment's layout is expected to contain a TextView with ID text_title. Here's how it's handled from the BaseFragment's onViewCreated():

TextView title = view.findViewById(R.id.text_title);
// Do something with the view from the base class

Now the ViewBinding-API generates binding-classes for each child-Fragment. I can reference the views using the binding. But I can't using the concrete Bindings from the base class. Even with introducing generics to the base class there are too many types of fragment-bindings that I discarded this solution for now.

What's the recommended way of handling the binding's views from the abstract base class? Are there any best-practices? Didn't found a built-in mechanism in the API to handle this scenario in an elegant way.

When the child-fragments are expected to contain common views, I could provide abstract methods that return the views from the concrete bindings of the Fragments and make them accessible from the base class. (For example protected abstract TextView getTitleView();). But is this an advantage rather than using findViewById()? What do you think? Any other (better) solutions? Please let's start some discuss.

Answer

Chetan Gupta picture Chetan Gupta · Dec 6, 2020

Hi I have created a blog post which covers view-binding in-depth, and also includes both composition patter/delegate pattern to implement view binding as well as using inheritance checkout from the link

checkout for complete code of BaseActivity and BaseFragment along with usage

👉Androidbites|ViewBinding

/*
 * In Activity
 * source : https://chetangupta.net/viewbinding/
 * Author : ChetanGupta.net
 */
abstract class ViewBindingActivity<VB : ViewBinding> : AppCompatActivity() {

    private var _binding: ViewBinding? = null
    abstract val bindingInflater: (LayoutInflater) -> VB

    @Suppress("UNCHECKED_CAST")
    protected val binding: VB
        get() = _binding as VB

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        _binding = bindingInflater.invoke(layoutInflater)
        setContentView(requireNotNull(_binding).root)
        setup()
    }

    abstract fun setup()

    override fun onDestroy() {
        super.onDestroy()
        _binding = null
    }
}
/*
 * In Fragment
 * source : https://chetangupta.net/viewbinding/
 * Author : ChetanGupta.net
 */
abstract class ViewBindingFragment<VB : ViewBinding> : Fragment() {

    private var _binding: ViewBinding? = null
    abstract val bindingInflater: (LayoutInflater, ViewGroup?, Boolean) -> VB

    @Suppress("UNCHECKED_CAST")
    protected val binding: VB
        get() = _binding as VB

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = bindingInflater.invoke(inflater, container, false)
        return requireNotNull(_binding).root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        setup()
    }

    abstract fun setup()

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

For usage, advance pattern and antipattern checkout blog Androidbites|ViewBinding