jetc.dev Newsletter Issue #80
This week, we explore the use cases for
as part of a Compose UI migration process, and see what decompiled composables look like.
And, I encourage you to check your use of custom views now, before you start trying to
convert them to composables.
One Off the Stack, One Off the Slack
You’ve got questions. That’s understandable!
Sometimes, you need to explicitly declare your fill weights — like we used to
LinearLayout — in order to get the UI that you want, as we see in
this week’s highlighted Stack Overflow question.
Vishnu Haridas suggested highlighting this Kotlinlang
#compose Slack thread, where we examine
the situations where we need
rememberUpdateState() and see why sometimes it appears
that we can skip it.
Posts, videos, and other new information related to Jetpack Compose!
Nate Ebel is migrating an app to Compose UI and brings us a screencast reviewing
a series of tips based on that work. These include how to set up your composable
APIs, how to make effective use of custom themes, and how to make the most of
Ruben Quadros blends the Paging 3 library with Compose UI to populate a two-up grid of video games from RAWG, complete with tests!
Joe Birch returns, with the flip side to Compose migration: using
to wrap a
View in a composable. This is useful for cases where you have an elaborate
View — perhaps from a third-party library — and you are not prepared
to switch to a Compose UI equivalent at this time.
Rashad Sookram ran into problems getting Robolectric-based unit tests to properly
exercise composables. Fortunately, Rashad took some notes and explains what it took
ComposeTestRule working and from there getting composable tests to run.
Gustavo Fão Valvassori explores how to create composable editions of some of the animated loading indicators from AVLoadingIndicatorView: bouncing balls, exploding circles, and spinning triangles.
Other Interesting Links
- Medium: How To Display Multiple Android Bottom Sheets in Jetpack Compose
- Medium: Getting started with jetpack compose — ConstraintLayout
- KoMPose Kit: KaMP Kit Goes Jetpack Compose
- 70+ Jetpack Compose Android App Projects
100% pure code!
Takahiro Menju wondered what the Compose compiler plugin actually generates for our composables, leading to a Gradle plugin that decompiles the generated Kotlin into Java, so you can see exactly what is going on “under the hood”.
Konstantinos Lountzis implemented a “staged step bar”: a linear progress indicator
with specific sub-indicators for particular milestones in the progress. This is
available both as a
View and as a
Other Interesting Links
- GitHub: umutsoysl / ComposeZoomableImage
- GitHub: ramzan / Atmostate
- GitHub: hamurcuabi / ShimmerEffectWithJetPackCompose
- GitHub: MTomczynski / Ellipse
…And One More Thing
One of the first steps that some developers will take when migrating an app
from the classic
View system to Compose UI is to use
ComposeView. If the app
implemented its own custom views, you could “simply” replace the implementation of the
custom view with a
ComposeView and composables. In theory, nothing that uses the
custom view will be able to tell the difference.
This is only true for some values of “simply”, though.
One of the problems with the
View system is that so much of the API surface is
It is all but impossible to enforce encapsulation this way. For some developers, it
will seem easier to change the custom view by using
findViewById() to poke around its
innards, rather than by actually changing the custom view itself. The problem is that
findViewById() calls will fail once the custom view changes implementation
to something radically different… and Compose UI definitely qualifies as “radically different”.
If you maintained good discipline with your use of custom views, this will not be an issue. If discipline was lacking, though, then you might find yourself needing to do some cleanup first.
One way to approach this is to try to eliminate all
findViewById() calls, such as by
adopting view binding. The nice thing about view binding is that it helps enforce
this sort of encapsulation: an outside consumer of a custom view does not have access
to the binding object of the custom view itself.
(and, if for some reason you made the binding object part of the custom view’s public API… well, perhaps that was not a good choice)
So, as you clean up lingering
findViewById() calls, you will find where you are “reaching into”
a custom view from outside, and can switch that to use a proper API on the custom
findViewById() might be the worst problem, but it is not the only one. For example,
consumers of a custom view might assume that the custom view extends from some particular
View subclass and use an API unique to that subclass. This will break once you change
the base class of the custom view to
ComposeView. Those might be the sort of thing that
you just deal with at the time of migrating the custom view to use composables.
This sort of thing is not unique to adopting Compose UI, as you can have encapsulation problems in any code. However, Compose UI migrations might stress your UI implementation in ways that expose encapsulation problems that you might not have considered otherwise.
And now, if you will excuse me, I need to go enter some tickets into Jira. Just sayin’. 😅
- 2023-11-21: Compose/Material3/Wear Compose updates! remember()! Adaptive layouts! Compose Multiplatform in 2024! @firstname.lastname@example.org on BasicTextField2()! Compose Multiplatform charts! And... is TV Compose in trouble?!?
- 2023-11-14: Compose Compiler! BasicTextField2()! @email@example.com and animations! Optimization! @firstname.lastname@example.org, JetBrains, and Fleet! JetBrains and plotting! And... we collapse?!?
- 2023-11-07: Compose Multiplatform! Chips in fields! Diffing! Custom fonts in Glance app widgets! Heatmaps! PIN input! And @email@example.com is in a bit of a haze?!?