Yet Another View binding Article?

android Dec 06, 2020

Synthetics import are deprecated, ViewBinding is the new norm.



AndroidBoss #Issue16

Issue 16

OnCreate Digest #Issue34

onCreate Digest - Issue #34
onCreate Digest is a weekly newsletter with links to Android Development related content.
view-binding

Sections

There are many view binding articles out now, what values does it add? after completing this one you would be familiar with these points

  1. Setup View Binding 🛠
  2. Location of Generated Files 🏠
  3. Generated Xml class 🖇 Format
  4. Generated View Field Name 🖇
  5. View Reference is never null? 🤥Nullable Generated Field
  6. Generated Fields for `Include` and `Merge` Tags 🧐
  7. Functions in binding class 🧛🏼‍♀️
  8. How to ignore view from generation 😵
  9. Binding in Activity 👼
  10. Binding in Fragments 😈
  11. Inflate vs Bind
  12. Binding In Recycler Adapter 🤖
  13. Binding ViewGroups|CompoundViews|CustomViews 👾
  14. Reducing the boiler plate | Delegate Pattern 👨🏻‍💻
  15. Reducing the boiler plate | Base Classes 👨🏻‍💻❤️
  16. Bonus | Common mistake | Double Inflating
  17. Bonus | Anti Pattern in Fragments
  18. Bonus | Anti Pattern in Adapters
  19. Bonus | Cleaner Code

Release Kotlin 1.4.20 · JetBrains/kotlin
CHANGELOG Android KT-42121 Deprecate Kotlin Android Extensions compiler plugin KT-42267 Platform declaration clash error in IDE when using kotlinx.android.parcel.Parcelize KT-42406 Long or infinit...
--

Kotlin 1.4.20 release on 19th-Nov, It’s a welcome release like always, but it deprecated Kotlin-Android-Extensions compiler plugin, means no more synthetic imports, If you don’t know about it then check this commit message. They have accounted that in Jan-2019, since then they have given enough time to devs to migrate to their official solution - ViewBinding or DataBinding


It’s really sad it was that it was the only zero boiler plate solution we had, but now it’s gone, and ViewBinding is here to stay. So here are 15 things you need to know about ViewBinding.


Setup View Binding 🛠

Docs does pretty much great job explaining how to step up View binding, a point of interest  I would like to add is to know your gradle plugin version. If your on Gradle plugin is 3.6.0, you need to modify build.gradle using this :

// https://developer.android.com/studio/releases/gradle-plugin#3-6-0
// Available in Android Gradle Plugin 3.6.0
android {
    ...
    viewBinding {
        enabled = true
    }
}
setup view-binding

If your Gradle plugin is 4.0.0, you need to modify build.gradle like this:

// https://developer.android.com/studio/releases/gradle-plugin#4-0-0
// Available in Android Gradle Plugin 4.0
android {
    ...
    buildFeatures {
        viewBinding true
    }
}
setup view-binding

Each module need to have this feature enabled in order to generate binding classes, it wouldn’t work if you just add this flag enabled in app module and not in rest of the feature module .i.e every feature module need to have this flag enabled.

Enjoying the Post?

a clap is much appreciated if you enjoyed. No sign up or cost associated :)

If you want to support my content do consider dropping a tip/coffee/donation💰


Location of Generated Files 🏠

Fun fact, even though library is called ViewBinding, but the package in which it generates XML binding classes is called databinding 😛, after completing setup of view binding you just need to rebuild your project in-order to make them visible.

You can find them at :
<Module-Name>/build/generated/data_binding_base_class_source_out/debug/out/<package-Name>/databinding/

example :
app/build/generated/data_binding_base_class_source_out/debug/out/com/example/ch8n/databinding
file path of binding class

This is to check the source code of generated file because the Android-Studio on navigation will take you to xml layout file not to the binding file.


Generated Xml class 🖇 Format

In ViewBinding, every XML layout file in a module gets a corresponding generated binding class, whose name is in Pascal Case format, with the word Binding appended at the end and implements ViewBinding interface.

Incase you don't know about PascalCase        
- PascalCase: NewObject;
- CamelCase: newObject;
- PascalCase: LongFunctionName()
- CamelCase: longFunctionName()

// fun fact 2, `Compose UI Framework` functions are all in `PascalCase`

For example,

// file name : profile_layout.xml
<FrameLayout ... >
    <TextView android:id="@+id/text_name" ... />
    <ImageView android:id="@+id/image_avatar" ... />
    <Button android:id="@+id/button_support_me" ... />
</FrameLayout>

Generated Class Name will look like,

public final class ProfileLayoutBinding implements ViewBinding {
  ...
}
Note: Generated class is in Java not Kotlin

Note : Files are generated into Java not Kotlin, reason for that would be discussed later, but it has nothing todo with interops between Java-Kotlin


Generated View Field Name 🖇

// file name : profile_layout.xml
<FrameLayout ... >
    <TextView android:id="@+id/text_name" ... />
    <ImageView ... />
    <Button android:id="@+id/button_support_me" ... />
</FrameLayout>
sample xml

This class has two fields: a TextView called text_name and a Button called button_support_me. The ImageView in the layout has no ID, so there is no reference to it in the binding class.

So the generated class would have fields like,

public final class ProfileLayoutBinding implements ViewBinding {
	//---- Root View is always generated ---//
    @NonNull
    private final FrameLayout rootView; 
	
    @NonNull
    public final Button buttonSupportMe;
    
    @NonNull
    public final TextView textName;
  	
    ...
}
sample generated class

Note : Root view always get generated, it doesn't require any Id to be given, but `child-views` requires an `Id` to get generated into the binding class

View Reference is never null? 🤥 Nullable Generated Field

When a view is not present in all of the configurations of the layouts, the field reference containing in its binding class will be marked as @Nullable

App resources overview | Android Developers
Read more on Android Config

Example:

// file : res/layout/profile_layout.xml
<FrameLayout ... >
    <TextView android:id="@+id/text_name" ... />
    <Button android:id="@+id/button_support_me" ... />
</FrameLayout>


// file : res/layout-sw600dp/profile_layout.xml
<FrameLayout ... >
    <TextView android:id="@+id/text_name" ... />
    <ImageView android:id="@+id/image_avatar" ... />
    <Button android:id="@+id/button_support_me" ... />
</FrameLayout>
sample xml file

Generated file would be having

public final class ProfileLayoutBinding implements ViewBinding {
  @NonNull
  private final FrameLayout rootView;
  @NonNull
  public final Button buttonSupportMe;
  @NonNull
  public final TextView textName;
  
  //------
  @Nullable
  public final ImageView imageAvatar;
  //------
  ...
}
sample generated class

from the above example, ImageView imageAvatar is marked as @Nullable because it is present in layout-sw600dp/profile_layout.xml but not in  layout/profile_layout.xml, i.e it's not contained into all the configurations layouts.


Generated Fields for `Include` and `Merge` Tags 🧐

Included Layout

  • Note that for using included layout with <include> tag needs to have an id: android:id="@+id/includes". This is required for View binding to generate the binding class like normal layout.
  • In case of included layouts, View Binding will first generate the binding class of the included layout, then add that as a field reference into the Parent Binding class.
// file name : profile_layout.xml
<FrameLayout ... >
    <TextView android:id="@+id/text_name" ... />
    
    <!-- include layout example -->
    <include
      android:id="@+id/includes"
      layout="@layout/included_layout" />

</FrameLayout>

// file name : included_layout.xml
<LinearLayout ... >
    <TextView android:id="@+id/text_demo1" ... />
</LinearLayout>
sample xm file - include

Generated class would look like.

public final class ProfileLayoutBinding implements ViewBinding {
  @NonNull
  private final FrameLayout rootView;

  @NonNull
  public final TextView textName;

	//------
  @NonNull
  public final IncludedLayoutBinding includes;
  	//------
  ...
}

public final class IncludedLayoutBinding implements ViewBinding {
	// this rootView is parent of included layout
    @NonNull
    private final LinearLayout rootView;
    
    @NonNull
    public final TextView textDemo1;
  	...
}
sample generated class - include

Use in codebase like :

// access to included files
binding.includes.textDemo1
sample access binding class

Enjoying the Post?

a clap is much appreciated if you enjoyed. No sign up or cost associated :)

If you want to support my content do consider dropping a tip/coffee/donation💰


Merged Layout

  • When we include layout  with <merge> tag, the system ignores the <merge> element and its child views directly added into the layout, in place of the <include/> tag.
  • As per this behaviour, View binding should have generated the fields automatically inside the included parent binding class but unfortunately that doesn't happen.
  • Even if you try to provide an ID to the included layout with merge tag, it will generate the rootView inside the binding class, but on runtime it will crash the app, with missing id exception, this behaviour is obvious as findViewById cannot get the root view of the merged layout as it has been flatten out by the system to be included inside the parent layout.
// file name : profile_layout.xml
<FrameLayout ... >
    <TextView android:id="@+id/text_name" ... />
    
    <!-- include layout example -->
    <include
      android:id="@+id/merges" [❌ wrong!]
      layout="@layout/merged_layout" />
    
    <!-- merge layout example --> 
    <include layout="@layout/merged_layout" /> [✅]
    
</FrameLayout>


// file name : merged_layout.xml
<merge ... >
    <TextView android:id="@+id/text_demo2" ... />
</merge>
sample xml file - merge

Generated class for merged layout would be

public final class ProfileLayoutBinding implements ViewBinding {
  @NonNull
  private final FrameLayout rootView;

  @NonNull
  public final TextView textName;
  
  [❌] no merged field should be there, we need to manually bind it

  ...
}

public final class MergedLayoutBinding implements ViewBinding {
	
  //-----
  @NonNull
  private final View rootView;
  //-----
  
  @NonNull
  public final TextView textDemo2;
  ...
}

Manually Binding the Merged Layout :

val parentBinding = ProfileLayoutBinding.inflate(..)
val mergedBinding = MergedLayoutBinding.bind(parentBinding.root)

Use in codebase like :

// access to included files
parentBinding.textDemo1
mergedBinding.textDemo2

Note: Due to this limitation of ViewBinding, we need to maintain multiple binding variables, which we have to manually release when the view is destroyed, we will discuss down the article how to release them.

Functions in binding class 🧛🏼‍♀️

Every binding class also includes a getRoot() method which comes from ViewBinding Interface, providing a direct reference to the root view of the corresponding layout file.

In this example, the getRoot() method in the ProfileLayoutBinding class returns the FrameLayout root view.

Other than that it exposes three public static functions to create a binding object

  • inflate(inflater) – Use this in an Activity onCreate() where there is no parent view to pass to the binding object.
  • inflate(inflater, parent, attachToParent) – Use this in a Fragment or a RecyclerView Adapter (or ViewHolder) where you need to pass the parent ViewGroup to the binding object.
  • bind(rootView) – Use this when you’ve already inflated the view and you just want to use view binding to avoid findViewById.

How to ignore view from generation 😵

Until now you understand that if you don't provide id to a view it will not generate the field into the binding class, but the ViewBinding class will always be generated with all its functions stated in point-7, but if you don't even want that to be generated and save some compilation time then add this attribute tools:viewBindingIgnore="true" to the root view of that xml layout file. Example:

<LinearLayout
        ...
        tools:viewBindingIgnore="true" >
        ...
</LinearLayout>
sample xml - ignore binding

Binding in Activity 👼

Binding in activity looks like:

// In activity class
private lateinit var binding: ProfileLayoutBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // activity already provide you with an instance of layoutInflater
    binding = ProfileLayoutBinding.inflate(layoutInflater)
    val view = binding.root
    setContentView(view)
}
sample binding activity

You can now use the binding variable to reference any of the views:

binding.name.text = "ch8n"
binding.button.setOnClickListener { "sample message".toToast() }
sample binding activity

Enjoying the Post?

a clap is much appreciated if you enjoyed. No sign up or cost associated :)

If you want to support my content do consider dropping a tip/coffee/donation💰


Binding in Fragments 😈

Doing binding in fragment isn't that straight forward as in Activity, If you use the similar way like making a global variable of the binding class in the fragment, this could lead to a memory leak, because the fragment outlives the view. So clearing the reference in onDestroyView is one way to handle it. For instance,

// In Fragment class

private var _binding: ProfileLayoutBinding? = null

// This property is only valid between onCreateView and onDestroyView.
private val binding 
	get() = _binding?: throw IllegalStateException("Cannot access view in after view destroyed and before view creation")

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = ProfileLayoutBinding.inflate(inflater, container, false)
    val view = binding.root
    return view
}

override fun onDestroyView() {
    super.onDestroyView()
    //Fragments outlive their views. Make sure you clean up any references to the 
    //binding class instance in the fragment's onDestroyView() method.
    
    _binding = null
}
sample binding fragment -1 

Another solution to deal with it is to move the reference to the correct scope. In Fragments, the inflate() method requires you to pass in a layout inflater. If the layout has already been inflated, you can instead call the binding class's static bind() method.

class ProfileFragment : Fragment(R.layout.profile_layout) {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val binding = ProfileLayoutBinding.bind(view)
        binding.textName.text = "ch8n"
        // problem with this is to accessing binding variable into global
        // space wont be possible and would require a global instance and
        // clearing in onDestroyView or rebinding of view in the other scope.
    }
}
sample binding fragment - 2
Note: avoid calling bind multiple times,as everytime you call bind function it will trigger findViewById, which will re-initialise all the binding fields.

Checkout this article to know more when to use lateinit and when to use nullable for a field

AndroidBites | Your Late to init | lateinit vs nullable
how kotlin null handle. how lateinit is better than nullable type. Nullable is not evil. nullable type vs lateinit. how to null handle in android. global variables .


Inflate vs Bind 🥊

Bind()

It internally uses findViewById on the view you have passed to initialise generated view fields of that binding.

//Signature
@NonNull
public static ProfileLayoutBinding bind(@NonNull View rootView){...}
sample bind function

If you look at it’s generated code, it would look a bit longer and very repetitive, including lots of nullability check on each field for performing null safe calls on findViewById. This is done on purpose so that the generated class has the best optimised compiled bytecode for size and performance, also this is the reason why the generated file is in Java not in Kotlin, because of the bytecode generated by Kotlin would be greater than that of Java.

You can checkout JakeWarton Blog explaining how the bytecode optimizing works for ViewBinding.

Optimizing Bytecode by Manipulating Source Code – Jake Wharton

Inflate()

The bind(rootView) function is responsible for binding all the views, but it requires View object to work, Inflate creates that for it, Inflate uses LayoutInflater to generate the View and pass it to Bind()

@NonNull
public static ActivityDetailBinding inflate(
  @NonNull LayoutInflater inflater,
  @Nullable ViewGroup parent, 
  boolean attachToParent
) {..}
sample inflate function

Since, View Inflation is an expensive task, inflate() will always be slower than bind(), but the catch in using bind() is that you must have the view instance, also keep in mind whenever you're calling bind() you're re-initialising all the binding variables using findViewById i.e. the view hierarchy is walked each time to find it.


Enjoying the Post?

a clap is much appreciated if you enjoyed. No sign up or cost associated :)

If you want to support my content do consider dropping a tip/coffee/donation💰


Binding In Recycler Adapter 🤖

Note : Don’t forget to check the Anti-pattern related to AdapterBinding at the end.
Binding in Recycler are easier just follow these steps:

// 1. inflate layout inside onCreateViewHolder
class SampleAdapter : RecyclerView.Adapter<YourViewHolder>(){
  ...
  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): YourViewHolder {
      val binding = ProfileLayoutBinding.inflate(
          LayoutInflater.from(parent.context),
          parent,
          false
      )
      // 2. pass binding object not the view
      returnYourViewHolder(binding)
  }
  ...
}

class YourViewHolder(
  binding: ProfileLayoutBinding
) : RecyclerView.ViewHolder(/* 3.pass root as view*/ binding.root){
    
    // 4. Bind your view using binding variables
    val name = binding.name
    
    fun bind(){
    	// 5.access your views
        name.setText("ch8n")
    }
}
sample binding in adapter

Adapters in fragment always leak when they are not released, so make sure you null the adapter reference you hold in your fragment's onDestroyView().


Binding ViewGroups | CompoundViews | CustomViews 👾

You can use init block to apply your views,

AndroidBites | Init Blocks will never haunt you again
kotlin init block order | kotlin default constructor | java init block | java static block | kotlin companion | kotlin companion init | java initialization block | kotlin object initialization | Example | show init block works | how to init block kotlin | primary constructor in kotlin
if you don’t know about init blocks do checkout:
// layout file => avatar_layout.xml
class AvatarView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {

    private lateinit var binding: AvatarLayoutBinding

    init { 
        // inflate binding and add as view
        binding = AvatarLayoutBinding.inflate(
            LayoutInflater.from(context), 
            this, 
            true
        )
        addView(binding.root)
    }
     
    fun setData(image: Bitmap, name: String, email: String) = with(binding) {
        image.setImageBitmap(image)
        name.text = name
        email.text = email
    }

}
sample binding in custom view

Reducing the boiler plate | Delegate Pattern 👨🏻‍💻

Curtsy of EpicPandaForce aka Gobar Varadi 🧠, Copy-paste his snippets into your code-base.

Simple one-liner ViewBinding in Fragments and Activities with Kotlin
There’s a new feature in Android Studio 3.6 called “view binding”. It’s just like databinding, except all it does is take your existing layout, and generate a binding for it — no changes necessary…

After pasting these snippets, Use it like this:

class ProfileActivity : AppCompatActivity() {
    private val binding by viewBinding(ProfileLayoutBinding::inflate)
    // use binding freely... no need to clear it out!
}

class ProfileFragment : Fragment(R.layout.profile_layout) {
    private val binding by viewBinding(ProfileLayoutBinding::bind)
    // use binding freely... no need to clear it out!
}
delegate view binding


Reducing the boiler plate | Base Classes 👨🏻‍💻❤️

Make this as your BaseActivity class

// Author : ChetanGupta.net @Androidbites
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
    }
}
base class activity

Make this as your BaseFragment

// Author : ChetanGupta.net @Androidbites

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
    }
}
base class fragment

Use it like :

class ProfileActivity :ViewBindingActivity<ProfileLayoutBinding>() {
  
  override val bindingInflater: (LayoutInflater) -> ViewBinding 
          = ProfileLayoutBinding::inflate
          
  override fun setup(){
  	//.. do stuff with binding variable
  }
}

class ProfileFragment :ViewBindingFragment<ProfileLayoutBinding>() {
  override val bindingInflater: (LayoutInflater) -> ViewBinding 
          = ProfileLayoutBinding::inflate
          
  override fun setup(){
  	//.. do stuff with binding variable
  }
}

Bonus | Common mistake | Double Inflating

Double Inflating

In Activity, Calling setContentView(…) with the layout resource id  instead of binding.root would causes the layout to be inflated twice and listeners to be installed on the wrong layout object.

// in activity
private lateinit var binding: ProfileLayoutBinding
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.profile_layout) [ ❌ ]
    binding = ProfileLayoutBinding.inflate(layoutInflater)
}
Double inflate activity

// in fragment
class ProfileFragment : Fragment() {
    
override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val rootView = inflater.inflate(R.layout.profile_layout,container, false)
    return rootView
}  

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val binding = ProfileLayoutBinding
            .inflate(LayoutInflater.from(requireContext()))  [ ❌ 🙅‍♀️ dont do it]
    }
}
Double inflate fragment

Enjoying the Post?

a clap is much appreciated if you enjoyed. No sign up or cost associated :)

If you want to support my content do consider dropping a tip/coffee/donation💰


Bonus | Anti Pattern in Fragments

// in fragments
private var _binding: ProfileLayoutBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val rootView = inflater.inflate(R.layout.profile_layout,container, false)
    _binding = ProfileLayoutBinding.bind(rootView) [ ❌ 🙅‍♀️ can be done but dont do it]
    return rootView
}
Anti pattern in fragment

Bonus | Anti Pattern in Adapters

// In Adapters
class SampleAdapter : RecyclerView.Adapter<YourViewHolder>(){
  ...
  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): YourViewHolder {
      val binding = ProfileLayoutBinding.inflate(
          LayoutInflater.from(parent.context),
          parent,
          false
      )
      [❌🙅‍♀️ can be done but dont do it]
      return YourViewHolder(binding.root)
  }
  ...
}

class YourViewHolder(
  view: View
) : RecyclerView.ViewHolder(view){
    
    //----
    [
     🧐 can be done but, this is fine upto a point
     
	 Reason 1 :
     Inflate internally called bind for you, why to waste bind call
     and rebind it again?
     
     Reason 2 :
     Since you're binding it here now this binding variable is owned 
     by the instance of viewholder and would be released only when 
     this instance will be nulled out and GC collected, I don't know
     when that happen, isRecycled callback only reuses this viewholder
     instance not release it. So anyone expert in recyclerView can
     provide some advice would be great, but IMO its okish, but avoid
     when you can.
     ]
     
    val binding = ProfileLayoutBinding.bind(view)
    //----
    
    val name = binding.name
    fun bind(){
        name.setText("ch8n")
    }
}

-------------------
------ OR --------
-------------------

class YourViewHolder(
  view: View
) : RecyclerView.ViewHolder(view){
   
    fun bind(){
    	[❌🙅‍♀️ can be done but dont do it, You on re-binding
        	everytime, this is bad.]
	    val binding = ProfileLayoutBinding.bind(view)
        binding.name.setText("ch8n")
    }
}


Anti pattern in adapter

Bonus | Cleaner Code

Instead of repeatedly writing binding in front of every view you can use scope functions to make it neat. For Instance,

// In Activities

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ProfileLayoutBinding.inflate(layoutInflater)
    setContentView(binding.root)
    setup()
}

fun setup() = with(binding){
	name = "ch8n"
    twitter = "@ch8n2"
    // do other stuff..
}


// In fragments

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val binding = ProfileLayoutBinding.bind(view)
        binding.text_name.text = "ch8n"
        setup(binding)
}

fun setup(binding:ProfileLayoutBinding)= with(binding){
	name = "ch8n"
    twitter = "@ch8n2"
   // do other stuff..
}
clearn code 

Conclusion 💆🏻‍♀️

That's all to the View-Binding, major concept of using it is to be aware of Bind and inflate function.

Hope you find it informative and if you have any feedback or post request or want to subscribe to my mailing list forms are below.

Do consider Clap to show your appreciation, until next time. Happy Hacking! 👩‍💻


Enjoying the Post?

a clap is much appreciated if you enjoyed. No sign up or cost associated :)

If you want to support my content do consider dropping a tip/coffee/donation💰


Reach me out :

Chetan Gupta
Software engineer 👨‍💻, Kotlin 🚀 Android 📱.



Chetan gupta

Hi there! call me Ch8n, I'm a mobile technology enthusiast! love Android #kotlinAlltheWay, CodingMantra: #cleanCoder #TDD #SOLID #designpatterns

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.