jetc.dev Newsletter Issue #80
Published: 2021-08-31
This week, we explore the use cases for rememberUpdateState()
, explore AndroidView()
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!
Implicit Layout Priorities
Sometimes, you need to explicitly declare your fill weights — like we used to
do with LinearLayout
— in order to get the UI that you want, as we see in
this week’s highlighted Stack Overflow question.
Why Do We Need rememberUpdateState()?
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.
Composable Commentary
Posts, videos, and other new information related to Jetpack Compose!
Video: 10 Jetpack Compose Tips From a Production Android App
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 @Preview
.
Learn with code: Jetpack Compose — Lists and Pagination (Part 1)
Ruben Quadros blends the Paging 3 library with Compose UI to populate a two-up grid of video games from RAWG, complete with tests!
Migrating to Compose - AndroidView
Joe Birch returns, with the flip side to Compose migration: using AndroidView()
to wrap a View
in a composable. This is useful for cases where you have an elaborate
custom View
— perhaps from a third-party library — and you are not prepared
to switch to a Compose UI equivalent at this time.
Testing Composables with Robolectric
Rashad Sookram ran into problems getting Robolectric-based unit tests to properly
exercise composables. Fortunately, Rashad took some notes and explains what it took
to get ComposeTestRule
working and from there getting composable tests to run.
Medium: Integrate Google sign in with Jetpack Compose
Rajesh Hadiya looks at how we can add the “Sign In with Google” button in a Compose UI
app, including integration with GoogleSignInClient
and launching the Google sign-in
activity.
Jetpack Compose Animations Beyond the State Change
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.
Medium: Display Map Snapshot using Jetpack Compose
Piotr Prus is back, using the Google Maps API to get snapshots of maps using AndroidView()
and MapView
, then taking the snapshots and displaying them in an Image()
composable.
Getting started with jetpack compose – Modifiers
Velmurugan wrote a long post with examples of 19 basic modifiers and what you get by using
them. This includes some less-common ones like rotate()
and shadow()
.
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
Resource Roundup
100% pure code!
GitHub: takahirom / decomposer
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”.
GitHub: kacmacuna / composed-xml
Bacho Kurtanidze implemented a “take a layout and generate a composable” tool, supporting both standard Compose UI and Compose for Desktop.
GitHub: loukwn / StageStepBar
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 StageStepBar()
composable.
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 public
.
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
those 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
view itself.
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’. 😅
Or, you can subscribe to the Atom feed or follow Mark Murphy in the Fediverse.
Recent Issues:
- 2024-12-10: A Compose Multiplatform alpha! Hot reload! Presentation! Sprites! Calendars!
- 2024-12-03: Rebecca Franks on clipping and masking! Stefano Natali on graphicsLayer()! FunkyMuse on type-safe nav results! And... if we have enough maps, do we need to store our maps in a Map?!?
- 2024-11-26: Math! Shared element transitions! Custom modifiers! Macrobenchmark! Adapting to platform-specific design systems! And... why does wrapContentSize() not wrap my content size?!?