« AsyncLayoutInflator

Introduction

The specific area that we’ll consider is layout inflation within our Activity. This can be a relatively slow process because it involves XML parsing and View object creation. The more complex our layout, then more work this requires.

This can be further slowed down if we are using the libraries such as Jetpack Navigation. When the NavHostFragment is inflated, this will require the navigation graph to then be inflated.

The inflation of the entire Activity layout hierarchy may take a little time. To give some basic idea: A layout consisting of a ConstraintLayout with a single TextView child takes around 100ms to inflate on a Pixel 3a XL. Obviously, a more complex layout may take considerably longer.

AsyncLayoutInflator

The Jetpack library named asynclayoutinflator does precisely that. It’s not a new library nor one which has many updates – it has been at release 1.0.0 since September 2018. The API itself is fairly straightforward. However, it may not be immediately clear how to use it with either Data Binding or View Binding. So we’ll actually look at how to implement it along with View Binding.

Let’s start by adding the library dependency:

implementation "androidx.asynclayoutinflater:asynclayoutinflater:1.0.0"

Our simple Activity looks like this:

1class MainActivity : AppCompatActivity() {
2
3 private lateinit var binding: ActivityMainBinding
4
5 override fun onCreate(savedInstanceState: Bundle?) {
6 super.onCreate(savedInstanceState)
7 setContentView(R.layout.activity_main)
8
9 val content = findViewById<ViewGroup>(android.R.id.content)
10
11 AsyncLayoutInflater(this).inflate(R.layout.activity_main, content) { view, _, _ ->
12 {
13 binding = ActivityMainBinding.bind(view)
14 setContentView(view)
15 }
16 }
17 }
18}

We first need to find the content view. This is the parent view which will hold the layout that we’ll inflate.

Next, we create an instance of AsyncLayoutInflater which takes a Context as it’s constructor argument.

We call the inflate() method on this to initialise the inflation.

The inflate() method takes three arguments: The first is the ID of the layout that will be inflated. The second is the parent view – in this case, it is the content view that we just obtained. The third is an instance of OnInflateFinishedListener which is a interface, so we can reduce its single method to a lambda. The lambda will be invoked once inflation is complete.

The lambda represents the onInflateFinished method of OnInflateFinishedListener. There are three arguments to this method: The first is the root view of the newly inflated view hierarchy. The second is the layout ID that was inflated. The third is the parent view – the content view that we passed to inflate().

We first bind our ActivityMainBinding to the new hierarchy using its static bind() method. We can now use the binding instance as we would normally use a View binding instance. Next we call setContentView() on the Activity to add the newly inflated view hierarchy as the Activity content. AsyncLayoutInflater does not add the inflated hierarchy to the parent ViewGroup so we need to do this manually. It is equivalent to calling:

layoutInflater.inflate(R.layout.activity_main, content, false)

Caution

It is worth remembering that performing different operations in parallel can result in race conditions. Therefore we must be careful to check that the binding instance has been initialised before we attempt to use it. For example, it may not have been initialised by the time onResume() is called. So we should check binding.isInitialized before using it in such cases.

Fragments

The next logical consideration is whether we should use this within Fragments for their layout inflation. Unfortunately AsyncLayoutInflator is not well suited to this because Fragments have layout inflation tied into their lifecycle methods. Whereas in Activity we typically perform layout inflation during onCreate(), in a Fragment we do it in onCreateView(). This method must return the inflated view hierarchy and using AsyncLayoutInflater within it does not allow this.

It is worth bearing in mind that most Activity layouts will be far more complex than those of Fragments. The latter are a smaller logical UI controller. So this may not be such a big deal. Typically it is Activities that will have NavHostFragment instances within their layouts, and any other embedded Fragment instances within the layout will also be inflated within the Activity‘s AsyncLayoutInflater invocation.

For full working code please visit

https://github.com/anishakd4/AsyncLayoutInflatorDemo