The Interesting case of ViewTree*Owner

Sidhant Rajora
3 min readOct 21, 2021

So, while building a sample app, I was famished by a very sketchy exception which is here down below

stack trace

I was bamboozled when I saw this error, as this was happening only, when I was inflating a ComposeView inside a fragment, if instead I inflate a layout using LayoutInflaterreturn it on onCreateView() the code was running as expected. I looked around on StackOverflow, issuetracker and few blogs, and they all suggested to update the appcompat to 1.3.0 or later, but I was already on 1.3.1 so, needed to figure out what went wrong where?

The Origin

So I started with a simple MainActivity and a project with viewBinding enabled, here is the snippet

So In here you can see, that I am using SampleBinding.inflate() and attachToRoot set to true, that basically attaches this layout to the window root, and shows it to the user, and I began my fragmentTransaction which tries to inflate a DemoFragment which in turn inflates a ComposeView like below

and when I ran it, it crashed with the above stack trace.

After looking into the ComposeView and AbstractComposeView , I came across a few code snippets which made me realize the obvious mistake that I was committing.

The Dig

So basically to lay out Composables we need a Recomposer which is just a Scheduler “for performing recomposition and applying updates to one or more Composition” this Recomposer which needs to know to what lifecycle this needs to be binded to, this is resolved via a few way which can be seen in the below snippet from ComposeView.android.kt

this is all to create a LifecycleAwareViewTreeRecomposer for obvious reasons. So at this point I knew that I messed up somewhere, and needed to know where, so I tried calling

ViewTreeLifecycleOwner.set(requireActivity().window.decorView, this)

before returning the ComposeView in the DemoFragment and it worked as expected.

but now to the main point, this can’t be the solution as I am going to do this manually for each and every fragment and that’s not the best solution.

The Solve

So, basically the whole concept of ViewTree*Owner was introduced recently, and there are three ViewTreeLifecycleOwner, ViewTreeViewModelStoreOwner and ViewTreeSavedStateRegistryOwner and there name are self explanatory about what they are owner of, and in the latest source of appcompat to be specific AppCompatActivity you see that we have setContnetView() method which inturn calls initViewTreeOwners() and that does the following.

it sets all of them. So if you go back to MainActivity you can see that I never called in the setContentView() with binding.root as parameter to it, thus skipping the call to initViewTreeOwners() thus the exception.

--

--