{"id":15179,"date":"2021-09-13T11:24:12","date_gmt":"2021-09-13T11:24:12","guid":{"rendered":"https:\/\/flobiz.in\/blog\/?p=15179"},"modified":"2021-09-19T10:56:10","modified_gmt":"2021-09-19T10:56:10","slug":"fragment-view-binding-initialisation-using-delegates","status":"publish","type":"post","link":"http:\/\/35.200.248.73\/blog\/fragment-view-binding-initialisation-using-delegates\/","title":{"rendered":"Fragment View Binding initialisation using Delegates"},"content":{"rendered":"\n<p id=\"1d0a\">View Binding in Android, allows us to seamlessly interact with the user interface by providing auto-generated classes for&nbsp;<em>each<\/em>&nbsp;XML layout (on a module by module basis).<\/p>\n\n\n\n<p id=\"2da5\">Therefore, a routine task of setting text in a TextView can be transformed from this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">val textView = findViewById&lt;TextView&gt;(R.id.text_view)<br>textView.text = \"Foo\"<\/pre>\n\n\n\n<p id=\"2760\">To this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">binding.textView.text = \"Foo\"<\/pre>\n\n\n\n<p id=\"6f66\">Of course, view binding requires some additional boilerplate code before we can use it. In the example above, we need to first initialise the&nbsp;<code>binding<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><em>\/\/ Step 1: Declare the binding<\/em><br><strong>private lateinit var binding: FragmentBuyBinding<\/strong>override fun onViewCreated(view: View, savedInstanceState: Bundle?) {<br>    super.onViewCreated(view, savedInstanceState)    \/\/ Step 2: Initialise it<br>    <strong>binding = FragmentBuyBinding.inflate(<em>layoutInflater<\/em>)<\/strong><br>    <br>    \/\/ Step 3: Access it<br>    <strong>binding.textView.<em>text <\/em>= \"Foo\"<\/strong><br>}<\/pre>\n\n\n\n<p id=\"3a48\">Doing this for each fragment in our project is cumbersome. So, can we do better? Is there a cleaner, more efficient way that decreases our boilerplate code? Yes! By leveraging the power of&nbsp;<strong>Delegates<\/strong>.<\/p>\n\n\n\n<p id=\"1397\">The article assumes you have already set up view binding in your project. If not, refer to this&nbsp;<a href=\"https:\/\/medium.com\/androiddevelopers\/use-view-binding-to-replace-findviewbyid-c83942471fc\">link<\/a><strong>&nbsp;<\/strong>to learn how to set it up.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"576b\">What are Delegates?<\/h2>\n\n\n\n<p id=\"34c8\">Delegation is defined as the shifting of responsibility for some particular work from one person to another. Simply put, you can think of delegation as a process in which one object delegates (assigns\/gives) a particular task to a helper object, called the&nbsp;<strong>delegate<\/strong>. It then becomes the responsibility of the delegate to execute the task and provide the result to our initial object. Kotlin inherently provides support for both class and property delegates. Since our&nbsp;<code>binding<\/code>&nbsp;object is a Fragment property, we\u2019ll be working with property delegates.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"800e\">Property Delegation<\/h3>\n\n\n\n<p id=\"adf4\">With property delegation, our delegate is responsible for handling the&nbsp;<code>get<\/code>&nbsp;and&nbsp;<code>set<\/code>&nbsp;for the specified property. We can thus abstract our common logic behind the delegate and re-use it for similar objects which in our case is the set of classes, auto-generated by view binding.<\/p>\n\n\n\n<p id=\"e299\">A thorough, more descriptive explanation of delegates can be found&nbsp;<a href=\"https:\/\/medium.com\/androiddevelopers\/delegating-delegates-to-kotlin-ee0a0b21c52b\">here<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"e941\">A Custom Property Delegate for Fragment View Binding<\/h3>\n\n\n\n<p id=\"2fab\">Without further ado, let\u2019s start writing our view binding delegate.<\/p>\n\n\n\n<p id=\"0564\"><strong>Step 1: Create the delegate class<br><\/strong>Create a new class&nbsp;<code>FragmentViewBindingDelegate.kt<\/code>&nbsp;and implement the&nbsp;<code>ReadOnlyProperty&lt;Fragment, T&gt;<\/code>&nbsp;interface. In case your property is mutable, you can use the&nbsp;<code>ReadWriteProperty&lt;Fragment, T&gt;<\/code>&nbsp;interface but since our&nbsp;<code>binding<\/code>&nbsp;is immutable, we only extend the read only interface. In addition, we require the binding class in our delegate constructor.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">class FragmentViewBindingDelegate&lt;T : ViewBinding&gt;(<br>    private val bindingClass: Class&lt;T&gt;<br>) : ReadOnlyProperty&lt;Fragment, T&gt; { }<\/pre>\n\n\n\n<p id=\"e685\"><strong>Step 2: Implement the&nbsp;<\/strong><code><strong>ReadOnlyProperty<\/strong><\/code><strong>&nbsp;interface<br><\/strong>As soon as we implement the&nbsp;<code>ReadOnlyProperty<\/code>&nbsp;interface, we are asked to implement the&nbsp;<code>getValue<\/code>&nbsp;member function.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">class FragmentViewBindingDelegate&lt;T : ViewBinding&gt;(<br>    private val bindingClass: Class&lt;T&gt;<br>) : ReadOnlyProperty&lt;Fragment, T&gt; {<br><br>    override fun getValue(thisRef: Fragment, property: KProperty&lt;*&gt;): T {<br>        \/\/ TODO<br>    }<br><br>}<\/pre>\n\n\n\n<p id=\"7e54\">The first param of&nbsp;<code>getValue()<\/code>&nbsp;is&nbsp;<code>thisRef<\/code>&nbsp;which represents the object that holds our property. It is of type&nbsp;<code>Fragment<\/code>&nbsp;in our case. The type for&nbsp;<code>thisRef<\/code>&nbsp;is governed by how we implement our interface. This is why we implemented&nbsp;<code>ReadOnlyProperty&lt;Fragment, T&gt;<\/code>&nbsp;instead of&nbsp;<code>ReadOnlyProperty&lt;Any?, T&gt;<\/code>.<\/p>\n\n\n\n<p id=\"a569\"><strong>Step 3: Implement&nbsp;<\/strong><code><strong>getValue<\/strong><\/code><strong><br><\/strong><code>getValue()<\/code>&nbsp;needs to return an instance of our&nbsp;<code>binding<\/code>&nbsp;object. So we create a variable called&nbsp;<code>binding<\/code>. In&nbsp;<code>getValue()<\/code>&nbsp;we initialise&nbsp;<code>binding<\/code>&nbsp;if it\u2019s not initialised and return it. This ensures we only initialise binding once and subsequently re-use the same instance.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">private var binding: T? = null<br>override fun getValue(thisRef: Fragment, property: KProperty&lt;*&gt;): T {<br>    if (binding == null)<br>        binding = bindingClass.getMethod(\"bind\", View::class.<em>java<\/em>).invoke(null, thisRef.requireView()) as T<br>    return binding!!<br>}<\/pre>\n\n\n\n<p id=\"9dfd\">At this point, we have handled most of our boilerplate code and can initialise our&nbsp;<code>binding<\/code>&nbsp;as:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">val binding by FragmentViewBindingDelegate(FragmentBuyBinding::class.<em>java<\/em>)<\/pre>\n\n\n\n<p id=\"50fd\">However, there are a few problems<br>1. The syntax to initialise&nbsp;<code>binding<\/code>&nbsp;can be improved<br>2. Our delegate is not lifecycle aware and thus, it will leak memory<\/p>\n\n\n\n<p id=\"e590\">Let\u2019s resolve them. Read on.<\/p>\n\n\n\n<p id=\"4df3\"><strong>Step 4: Clean our&nbsp;<\/strong><code><strong>binding<\/strong><\/code><strong>&nbsp;init syntax<br><\/strong>Our delegate requires the class of our generic&nbsp;<code>Class&lt;T&gt;<\/code>&nbsp;to return the correct view binding instance. Another way to get this information is by using the&nbsp;<code>reified<\/code><strong>&nbsp;<\/strong>keyword in Kotlin. You can learn more about reified&nbsp;<a href=\"https:\/\/blog.mindorks.com\/what-are-reified-types-in-kotlin\">here<\/a>.<\/p>\n\n\n\n<p id=\"d5a3\">Add this inline function outside your delegate class:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">inline fun &lt;reified T : ViewBinding&gt; Fragment.viewBinding() = FragmentViewBindingDelegate(T::class.<em>java<\/em>)<\/pre>\n\n\n\n<p id=\"d2ab\">Et voil\u00e0! You can now initialise your binding with a clean, concise syntax.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">private val binding by viewBinding&lt;FragmentBuyBinding&gt;()<\/pre>\n\n\n\n<p id=\"40b1\"><strong>Step 5: Make&nbsp;<\/strong><code><strong>FragmentViewBindingDelegate<\/strong><\/code><strong>&nbsp;lifecycle aware<br><\/strong>To make our delegate lifecycle aware we need to pass an instance of our host fragment to it.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">class FragmentViewBindingDelegate&lt;T : ViewBinding&gt;(<br>    private val bindingClass: Class&lt;T&gt;,<br>    private val fragment: Fragment<br>) : ReadOnlyProperty&lt;Fragment, T&gt; {<\/pre>\n\n\n\n<p id=\"da6e\">And, update our inline function.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">inline fun &lt;reified T : ViewBinding&gt; Fragment.viewBinding() = FragmentViewBindingDelegate(T::class.<em>java<\/em>, this)<\/pre>\n\n\n\n<p id=\"df11\">Finally, subscribe to the fragment\u2019s lifecycle and set the&nbsp;<code>binding<\/code>&nbsp;to&nbsp;<code>null<\/code>&nbsp;once the fragment is destroyed ensuring our delegate does not leak any memory.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">init {<br>    fragment.<em>lifecycle<\/em>.addObserver(object : DefaultLifecycleObserver {<br>        override fun onCreate(owner: LifecycleOwner) {<br>            fragment.<em>viewLifecycleOwnerLiveData<\/em>.<em>observe<\/em>(fragment) <strong>{ _<\/strong>viewLifecycleOwner <strong>-&gt;<br>                _<\/strong>viewLifecycleOwner.<em>lifecycle<\/em>.addObserver(object : DefaultLifecycleObserver {<br>                    override fun onDestroy(owner: LifecycleOwner) {<br>                        binding = null<br>                    }<br>                })<br>            <strong>}<br>        <\/strong>}<br>    })<br>}<\/pre>\n\n\n\n<p id=\"9937\">And we\u2019re done!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"5579\">Final Code<\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\">inline fun &lt;reified T : ViewBinding&gt; Fragment.viewBinding() = FragmentViewBindingDelegate(T::class.<em>java<\/em>, this)<br>class FragmentViewBindingDelegate&lt;T : ViewBinding&gt;(<br>    private val bindingClass: Class&lt;T&gt;,<br>    private val fragment: Fragment<br>) : ReadOnlyProperty&lt;Fragment, T&gt; {<br><br>    private var binding: T? = null<br><br>    init {<br>        fragment.<em>lifecycle<\/em>.addObserver(object : DefaultLifecycleObserver {<br>            override fun onCreate(owner: LifecycleOwner) {<br>                fragment.<em>viewLifecycleOwnerLiveData<\/em>.<em>observe<\/em>(fragment) <strong>{ <\/strong>viewLifecycleOwner <strong>-&gt;<br>                    <\/strong>viewLifecycleOwner.<em>lifecycle<\/em>.addObserver(object : DefaultLifecycleObserver {<br>                        override fun onDestroy(owner: LifecycleOwner) {<br>                            binding = null<br>                        }<br>                    })<br>                <strong>}<br>            <\/strong>}<br>        })<br>    }<br><br><br>    override fun getValue(thisRef: Fragment, property: KProperty&lt;*&gt;): T {<br>        if (binding == null)<br>            binding = bindingClass.getMethod(\"bind\", View::class.<em>java<\/em>).invoke(null, thisRef.requireView()) as T<br>        return binding!!<br>    }<br><br>}<\/pre>\n\n\n\n<p id=\"039b\">And in our fragment,<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">private val binding by <em>viewBinding<\/em>&lt;FragmentBuyBinding&gt;()<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Is there more efficient way that decreases our boilerplate code? Yes! By leveraging the power of Delegates.<\/p>\n","protected":false},"author":7,"featured_media":15285,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[149],"tags":[],"class_list":["post-15179","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-engineering-product"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v16.1.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Fragment View Binding initialisation using Delegates - Flobiz<\/title>\n<meta name=\"description\" content=\"About Fragment view Binding initialisation using Delegates. Read what are delegates, property delegation, custom property delegate for fragment view.\" \/>\n<link rel=\"canonical\" href=\"http:\/\/73.248.200.35.bc.googleusercontent.com\/blog\/fragment-view-binding-initialisation-using-delegates\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Fragment View Binding initialisation using Delegates - Flobiz\" \/>\n<meta property=\"og:description\" content=\"About Fragment view Binding initialisation using Delegates. Read what are delegates, property delegation, custom property delegate for fragment view.\" \/>\n<meta property=\"og:url\" content=\"http:\/\/73.248.200.35.bc.googleusercontent.com\/blog\/fragment-view-binding-initialisation-using-delegates\/\" \/>\n<meta property=\"og:site_name\" content=\"FloBiz\" \/>\n<meta property=\"article:published_time\" content=\"2021-09-13T11:24:12+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-09-19T10:56:10+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/35.200.248.73\/blog\/wp-content\/uploads\/2021\/09\/Untitled-design-5.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"675\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\">\n\t<meta name=\"twitter:data1\" content=\"5 minutes\">\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"http:\/\/35.200.248.73:80\/blog\/#website\",\"url\":\"http:\/\/35.200.248.73:80\/blog\/\",\"name\":\"FloBiz\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"http:\/\/35.200.248.73:80\/blog\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"ImageObject\",\"@id\":\"http:\/\/73.248.200.35.bc.googleusercontent.com\/blog\/fragment-view-binding-initialisation-using-delegates\/#primaryimage\",\"inLanguage\":\"en-US\",\"url\":\"http:\/\/35.200.248.73\/blog\/wp-content\/uploads\/2021\/09\/Untitled-design-5.png\",\"contentUrl\":\"http:\/\/35.200.248.73\/blog\/wp-content\/uploads\/2021\/09\/Untitled-design-5.png\",\"width\":1200,\"height\":675,\"caption\":\"Binding\"},{\"@type\":\"WebPage\",\"@id\":\"http:\/\/73.248.200.35.bc.googleusercontent.com\/blog\/fragment-view-binding-initialisation-using-delegates\/#webpage\",\"url\":\"http:\/\/73.248.200.35.bc.googleusercontent.com\/blog\/fragment-view-binding-initialisation-using-delegates\/\",\"name\":\"Fragment View Binding initialisation using Delegates - Flobiz\",\"isPartOf\":{\"@id\":\"http:\/\/35.200.248.73:80\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"http:\/\/73.248.200.35.bc.googleusercontent.com\/blog\/fragment-view-binding-initialisation-using-delegates\/#primaryimage\"},\"datePublished\":\"2021-09-13T11:24:12+00:00\",\"dateModified\":\"2021-09-19T10:56:10+00:00\",\"author\":{\"@id\":\"http:\/\/35.200.248.73:80\/blog\/#\/schema\/person\/9a658391bc1bd4a4dcb0c3eac063cae6\"},\"description\":\"About Fragment view Binding initialisation using Delegates. Read what are delegates, property delegation, custom property delegate for fragment view.\",\"breadcrumb\":{\"@id\":\"http:\/\/73.248.200.35.bc.googleusercontent.com\/blog\/fragment-view-binding-initialisation-using-delegates\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"http:\/\/73.248.200.35.bc.googleusercontent.com\/blog\/fragment-view-binding-initialisation-using-delegates\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"http:\/\/73.248.200.35.bc.googleusercontent.com\/blog\/fragment-view-binding-initialisation-using-delegates\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"item\":{\"@type\":\"WebPage\",\"@id\":\"http:\/\/35.200.248.73:80\/blog\/\",\"url\":\"http:\/\/35.200.248.73:80\/blog\/\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"position\":2,\"item\":{\"@type\":\"WebPage\",\"@id\":\"http:\/\/73.248.200.35.bc.googleusercontent.com\/blog\/fragment-view-binding-initialisation-using-delegates\/\",\"url\":\"http:\/\/73.248.200.35.bc.googleusercontent.com\/blog\/fragment-view-binding-initialisation-using-delegates\/\",\"name\":\"Fragment View Binding initialisation using Delegates\"}}]},{\"@type\":\"Person\",\"@id\":\"http:\/\/35.200.248.73:80\/blog\/#\/schema\/person\/9a658391bc1bd4a4dcb0c3eac063cae6\",\"name\":\"Sarthak Garg\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"http:\/\/35.200.248.73:80\/blog\/#personlogo\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/bee27a54b0195d4d219f0aeafd1062ca33346ad05c60e348ee63291170bdae4a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/bee27a54b0195d4d219f0aeafd1062ca33346ad05c60e348ee63291170bdae4a?s=96&d=mm&r=g\",\"caption\":\"Sarthak Garg\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","_links":{"self":[{"href":"http:\/\/35.200.248.73\/blog\/wp-json\/wp\/v2\/posts\/15179","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/35.200.248.73\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/35.200.248.73\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/35.200.248.73\/blog\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"http:\/\/35.200.248.73\/blog\/wp-json\/wp\/v2\/comments?post=15179"}],"version-history":[{"count":5,"href":"http:\/\/35.200.248.73\/blog\/wp-json\/wp\/v2\/posts\/15179\/revisions"}],"predecessor-version":[{"id":15377,"href":"http:\/\/35.200.248.73\/blog\/wp-json\/wp\/v2\/posts\/15179\/revisions\/15377"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/35.200.248.73\/blog\/wp-json\/wp\/v2\/media\/15285"}],"wp:attachment":[{"href":"http:\/\/35.200.248.73\/blog\/wp-json\/wp\/v2\/media?parent=15179"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/35.200.248.73\/blog\/wp-json\/wp\/v2\/categories?post=15179"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/35.200.248.73\/blog\/wp-json\/wp\/v2\/tags?post=15179"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}