CodeNewbie Community

Cover image for View Binding in Android with Kotlin
Tristan
Tristan

Posted on

View Binding in Android with Kotlin

Introduction

  • This series is not going to be in any particular order, so feel free to read whatever blog post you want. Anytime I find something that I think could use a blog post, I will write one and put it here

Setting up

  • So first things first, we need to enable view binding. Inside the module level gradle.build file(the build file with module written next to it) we place the buildFeatures block into the android block:
android{

buildFeatures {
        viewBinding true
    }

}
Enter fullscreen mode Exit fullscreen mode
  • This will enable the compiler to recompile the project and create ViewBinding object for each XML file.

What is a ViewBinding object?

  • a ViewBinding object is created for each layout file. By default, the name of the object is based on the name of the layout file, converting it to Pascal case and adding the Binding suffix to it. So if we had a layout file called main_fragment its corresponding ViewBinding object would be MainFragmentBinding. This object creates immutable fields for each view in out layout file that has an ID. So anything inside a layout file that has a android:id="" will get a field in the ViewBinding object with the same name. We can then use these fields to access the wanted view. Each ViewBinding object also has a static method called inflate() that we can use to inflate the view hierarchy.

Using view binding in Fragments

  • To use ViewBinding with a fragment we need to perform 3 mains steps:

1) Set up instance variable

2) Override the onCreateView() method

3) Override the onDestroyView() method

1) Set up instance variables

  • There are going to be two instance variables that we create when dealing with view binding:
private var _binding: NewCalfBinding? = null
private val binding get() = _binding!!
Enter fullscreen mode Exit fullscreen mode
  • Ignoring all the syntax, I want to draw your attention to NewCalfBinding this name is chosen because I have a XML layout file called new_calf. Make sure that you use the appropriate name for your code. Now in order to understand all the syntax lets talk a little about null inside of Kotlin

Null saftey

  • Kotlin has a type system that is aimed at eliminating the danger of NullPointerException. Unless explicitly stated that we will allow one, Kotlin helps us avoid NullPointerExceptions.

  • Kotlin distinguishes between references that can hold null(nullable references) and those that can not(non-null references). We the developer can use the ? operator to define a variable that is allowed to hold null. So the statement, private var _binding: NewCalfBinding? = null, is how we define a private variable called _binding of type NewCalfBinding and thanks to ? this variable can also hold null. Notice the error you get when you remove the ?.

The !! operator

  • The !! operator is called the not null assertion operator and it converts any value to a non-null type. If the value is null then it with throw an very specific NullPointerException. The !! operator is how we explicitly tell Kotlin we want to throw a NullPointerException

2) Override the onCreateView() method

  • The onCreateMethod() is called to have the fragment instantiate its user interface view. It will return the instantiated view. It is recommended to only inflate the layout in this method and move the logic that operates on the View to the onViewCreated() method.
override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = NewCalfBinding.inflate(inflater, container, false)
        val view = binding.root
        return view
    }
Enter fullscreen mode Exit fullscreen mode
  • As stated, this is the method where we inflate(create) our view. Also, notice the : View? indicating that this method can return View or null. The inflate() method is a static method that is defined on all of the ViewBinding objects. binding.root is how we get a reference to the root view (Constraint layout or what ever layout is surrounding all other views in the layout file ). Lastly we return the root view with return view.

Override the onDestroy() method

override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
Enter fullscreen mode Exit fullscreen mode
  • As you can see that this is fairly straight forward, when this method is called by the system we set our _binding variable back to null... but why? I have done some googling and mainly it comes down to memory leaks. If we do not set _binding = null this can lead to a memory leak which will lead to performance issues as our app scales. But lets go a little deep and try to understand the lifecycles and what is happening.

  • so to really understand what is going on you should read up on the Fragment's lifecycle documentation, especially the section on destroying views and fragments.

  • It is also important to point out that a fragment's view has a separate lifecycle that is managed independently from the fragment's lifecycle. So a Fragment can outlast a View

-But ultimately this is what happens: when the Fragment is no longer in view(visible to the user) and all the exit animations and transitions have been completed. The fragment's view will transition into it's DESTROYED state and emits a ON_DESTROY event to it's observer's(the Fragment). This then triggers the fragment to invoke its onDestroyView() method. It's documentation states, The next time the fragment needs to be displayed, a new view will be created. So we set _binding = null to allow for a new View to be created and referenced. Thus giving us a fresh View and no memory leaks

Conclusion

  • Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on Twitter.

Discussion (0)