article banner (priority)

Understand Compose in 3 minutes

This is a text-version of the video we published on YouTube.

UI developers are already used to a situation where they define a declarative structure and, poof, now they can see a UI.

But how does it actually work? React or Vue has its virtual DOM transformations, but Compose is completely different. It might surprise you, but in Compose the answer to this question lies in modifiers.

If you dive deep into any component, you will see that it is composed of one or more native components named Layout. The layout contains two or three things: first, a measure strategy that decides how much space a component takes and where it places itself. The measure strategy is often empty, as modifiers can make such decisions as well. It also contains modifiers that handle drawing, specify semantics, react to user interactions, and so on. Yes, modifiers are responsible for everything you can see or do in Compose! Your UI tree includes modifiers, layout-calculation functions, and relations! Relations are built by a third, optional parameter, that is, the layout content, which is called to build children during composition or update during recomposition.

compose_understand_3.png

So, how do modifiers work? Except for the factory function, which is defined to conveniently use modifiers, modifiers are defined by two classes. The first one is a modifier node element that manages modifier nodes by creating and updating them when needed. It is responsible for creating and updating modifier nodes. When a component gets recomposed, it might change, which means it might declare different modifier node elements.

In such cases, previous modifier node elements are compared to new ones. Most will stay the same, but some may be updated, created, or removed. This means updating previous nodes or changing what modifiers are used. This is how recomposition leads to UI changes.

Now let’s get back to modifier nodes, which are the heart of compose. Those are stateful classes responsible for drawing, layout, semantics, and more. How do they do that? They can implement certain interfaces. In different phases, Compose traverses the layout tree and invokes modifiers that define specific interfaces. For instance, during the drawing phase, Compose calls the method draw from all modifiers with DrawModifierNode. This is how practically everything you can see in Compose is drawn. When building a semantic tree, Compose uses modifiers that implement SemanticsModifierNode.

Some modifiers implement multiple interfaces. For instance, the modifier that is responsible for drawing text in the Text component implements DrawModifierNode to draw text, LayoutModifierNode to decide on component size based on constraints, and SemanticsModifierNode to add semantic properties.

This was the essence of how Compose works; all those topics are covered in much greater detail in my course, Advanced Compose, where we build a deep understanding of how Compose works and how to use it effectively in modern projects. I also include many Compose hints, including Kotlin and Coroutines, in my free mailing.