HomeAndroidViewCompositionStrategy Demystefied | by Chris Arriola | Android Builders | Might, 2023

ViewCompositionStrategy Demystefied | by Chris Arriola | Android Builders | Might, 2023


In Jetpack Compose, a Composition is a tree-like construction describing the UI of your app and is produced by operating composables. When the Composition is now not wanted, state will now not be tracked by Jetpack Compose, and the Composition will get disposed in order that sources could be launched.

ViewCompositionStrategy defines when the Composition must be disposed. The default, ViewCompositionStrategy.Default, disposes the Composition when the underlying ComposeView detaches from the window, until it’s a part of a pooling container comparable to a RecyclerView. Nevertheless, in case you are incrementally including Compose in your codebase, this conduct might trigger state loss in some situations. For instance, in case you are seeing bizarre glitches like scroll positions getting reset in your Fragment-based Compose app, maybe you might be utilizing the mistaken ViewCompositionStrategy (you need to be utilizing one of many Lifecycle-based methods as a substitute).

On this weblog submit, I’ll cowl what ViewCompositionStrategy is, why it’s wanted, and how one can choose the best technique on your use case to keep away from state loss.

TL;DR:

* Word: ComposeView is talked about for simplicity’s sake, although the identical behaviors apply for various types of AbstractComposeView.

For a extra in-depth understanding, maintain studying!

ViewCompositionStrategy impacts the disposal section of the Composition by robotically disposing the Composition when sure circumstances are met. As soon as the Composition is disposed, sources are cleaned up and state will now not be tracked by Compose.

The particular technique utilized will decide when the Composition must be disposed robotically. With no technique, you would need to explicitly name disposeComposition on the ComposeView to dispose the underlying Composition.

Fortunately, a default technique as outlined by ViewCompositionStrategy.Default, which is presently set to DisposeOnDetachedFromWindowOrReleasedFromPool, is already utilized while you create a ComposeView (or name setContent from a ComponentActivity) so in a overwhelming majority of circumstances, you received’t need to set it explicitly. Nevertheless, you possibly can change the default to a distinct technique by offering it by way of setViewCompositionStrategy.

In a single-Exercise Compose-only app, just one Composition is usually lively. I point out sometimes as a result of there are some exceptions to this — like subcomposition — however that’s out of scope for this weblog submit. Preliminary Composition happens when the Exercise is created. It runs the composables supplied inside setContent, and the Composition stays lively till the Compose content material is indifferent from the window — this detachment occurs when the Exercise is being destroyed. That is the default ViewCompositionStrategy of a ComposeView (extra on this beneath), and in a Compose-only app, this conduct is what you need.

Compose-only app with only one Composition

Every occasion of a ComposeView maintains its personal separate Composition. So, in case you are incrementally migrating your View-based app to Compose, you will have a number of Compositions. For instance, if in case you have a ViewPager2 paging via Fragments and every Fragment’s content material is in Compose, every ComposeView can be a separate Composition.

Combined View/Compose app whereby every ComposeView within the ViewPager2 maintains a separate Composition

The interplay between every Composition, and parts with a Lifecycle comparable to an Exercise or Fragment, is the explanation why you will have to vary the default ViewCompositionStrategy so that you’re disposing on the proper time.

When the technique is ready to DisposeOnDetachedFromWindow, the underlying Composition can be disposed when:

the ComposeView detaches from the window

So when does View detachment happen?

Usually, this occurs when the View goes off display screen and is now not seen to the person. Some situations embrace:

  • When the View is faraway from the View hierarchy by way of ViewGroup.removeView* APIs
  • When the View is a part of a transition
  • When the containing Exercise is being destroyed — after onStop, however earlier than onDestroy

Word you could take heed to window connect/detach occasions by setting a View.OnAttachStateChangeListener by way of addOnAttachStateChangeListener.

Earlier than Compose UI model 1.2.0-beta02, this technique was the default technique as it’s the popular technique for a majority of use circumstances. Nevertheless, since model 1.2.0-beta02, this default has been changed by DisposeOnDetachedFromWindowOrReleasedFromPool.

When a ComposeView is used inside a pooling container, comparable to a RecyclerView, View components are consistently being connected and reattached to the window as components are recycled because the UI scrolls. This implies when you use DisposeOnDetachedFromWindow, the underlying Composition of ComposeViews would additionally consistently bear preliminary Composition and disposals. Frequent disposing and recreating Compositions can damage scrolling efficiency, particularly when shortly flinging via the record.

To enhance upon this, DisposeOnDetachedFromWindowOrReleasedFromPool disposes the Composition when:

the ComposeView detaches from the window, until it’s a part of a pooling container comparable to a RecyclerView. When the Composition is inside a pooling container, it can dispose when both the underlying pooling container itself detaches from the window, or when the merchandise is being discarded (i.e. when the pool is full).

In different phrases, DisposeOnDetachedFromWindowOrReleasedFromPool is like DisposeOnDetachedFromWindow however with added performance.

In case you are inquisitive about how this works and why it was launched, take a look at Jetpack Compose Interop: Utilizing Compose in a RecyclerView.

When the technique is ready to DisposeOnLifecycleDestroyed, a Lifecycle or LifecycleOwner should be supplied and the underlying Composition will dispose when:

the supplied Lifecycle is destroyed. This technique is suitable when the ComposeView shares a 1–1 relationship with a recognized LifecycleOwner.

For example, the snippet beneath disposes the Composition when a Fragment’s lifecycle is destroyed:

This technique is useful in circumstances the place you wish to tie the Composition’s lifecycle to a recognized Lifecycle. The canonical instance of this can be a Fragment View whereby the View could be indifferent from the window (that’s, the Fragment is now not seen within the display screen), and the Fragment may not be destroyed but (onDestroy not but known as). This will occur on a ViewPager2’s Fragment Views as you web page via content material. When you have been to make use of both of the earlier methods, the Composition can be disposed prematurely, leading to potential state loss (for instance, scroll state in a LazyColumn wouldn’t be remembered).

A query you may ask your self is that this: “What if I’ve a ComposeView as an merchandise in a RecyclerView that’s inside a Fragment? Which technique ought to I exploit?” The quick ancestor will dictate which technique to use — so because the ComposeView is an merchandise in a RecyclerView, you’ll use DisposeOnDetachedFromWindowOrReleasedFromPool, in any other case, use DisposeOnLifecycleDestroyed.

A associated however different to the earlier technique is DisposeOnViewTreeLifecycleDestroyed. This technique can be utilized whether it is desired to tie the Composition lifecycle with a Lifecycle object, however the Lifecycle is just not recognized but. The underlying Composition will dispose when:

the ViewTreeLifecyleOwner of the following window the View is connected to is destroyed. This technique is suitable when the ComposeView shares a 1–1 relationship with their closest ViewTreeLifecycleOwner, comparable to a Fragment View.

For example, the snippet beneath exhibits a customized View that inherits from AbstractComposeView. The Composition can be disposed when the closest ViewTreeLifecycleOwner is destroyed because the ViewCompositionStrategy is modified to DisposeOnViewTreeLifecycleDestroyed:

Primarily, this works by discovering the related LifecycleOwner accountable for managing the ComposeView by utilizing the ViewTreeLifecycleOwner.get API.

A query you might need is, when ought to I exploit DisposeOnLifecycleDestroyed vs. DisposeOnViewTreeLifecycleDestroyed? If the Lifecycle object is already recognized, then use DisposeOnLifecycleDestroyed; in any other case, use DisposeOnViewTreeLifecycleDestroyed.

We coated all of the several types of ViewCompositionStrategy choices to make use of and the way choosing the best one in an interop state of affairs is essential to correctly eliminate the Composition. See the desk within the introduction of the submit as a reference for when you need to use what.

Have any questions? Depart a remark beneath!

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments