jetc.dev Newsletter Issue #134

Published: 2022-09-27

We got a new beta for Compose 1.3.0, and stuff keeps changing!

In addition, we look at animations and dual-pane UIs, plus steppers and lock patterns. However, a growing concern is performance, so we look at upcoming Flamingo composition tracing, and I worry about how weird our composables are going to get as we deal with this and other limitations.

Ooooo… What Did We Get?

Reviewing the release notes for the latest Jetpack Compose update!

Compose is out with a 1.3.0-beta03 release!

The big thing is that the lambdas that you pass to remember() and rememberCoroutineScope() are now considered to be crossinline. You cannot perform an early return from a crossinline lambda expression. That was never supported anyway, apparently, but now you get a clearer compiler error.

In addition, we got more stuff that seems like it should not be in a beta, such as:

  • Line-breaking options for Text()

  • A new withConsumedWindowInsets() modifier

  • An experimental pullRefresh() modifier for the popular pull-to-refresh pattern

(these are all great, but they feel more like changes that belong in an alpha, not a beta)

Wear Compose has a new 1.1.0-alpha06 release. In addition to fixing a PositionIndicator bug, they added a scrollAway() modifier for Column(), LazyColumn(), and ScalingLazyColumn(). The primary use case is to allow you to have the TimeText scroll with the content.

One Off the Stack, One Off the Slack

You’ve got questions. That’s understandable!

How Do We Control Text Overflow?

It’s a common requirement: you need something to immediately follow some text, remain close to the text (i.e., no extra whitespace), but also force the text to wrap or ellipsize to control maximum width. Learn about the fill parameter to the weight() modifier, and how it can help with this case, in this week’s highlighted Stack Overflow question.

How Do We Linkify Our Text()?

TextView has android:autoLink, backed by Linkify. This was handy but prone to problems. There is no direct analogue for Text() in Compose UI, but learn how to set it up yourself (and problems in doing so), in this week’s highlighted Kotlinlang #compose Slack thread.

Composable Commentary

Posts, videos, and other new information related to Jetpack Compose!

Medium: Jetpack Compose Composition Tracing

Google’s Ben Trengrove walks us through some new performance analysis options in the upcoming Flamingo version of Android Studio. Compose Composition Tracing marries the composable call stack with system traces, to help you identify what composables are contributing to hot spots in your app execution.

Medium: Composable Functions

Google’s Chris Arriola continues a series of posts on Compose basics, this time looking at what it means for a function to be “composable”, what “recomposition” means, and assumptions that you should avoid when creating your composables.

Video: Taking Jetpack Compose animations to the next level

Katie Barnett delivered a presentation for GDG Melbourne focusing on animations. There is a dizzying array of animation options for Compose; Katie looks at several options for animating cards (e.g., flipping cards from front to back).

Jetpack Compose Accompanist TwoPane

Kristen Halper returns, this time looking at the Accompanist TwoPane() composable, as a counterpart to Microsoft’s own take on that UI. While both are aware of foldables and can help you better work with that form factor, TwoPane() always shows both panes, whereas the Microsoft TwoPaneLayout() shows one or two panes based on device posture and other considerations.

Medium: Jetpack Compose Navigation Animation

Manshi Shah continues an exploration of Compose animation APIs started in this earlier Medium post. Here in Part 2, Manshi examines animated transitions with Navigation for Compose, using Accompanist for those navigation animations.

Compose UI for iOS

Júlia Jakubcová and Tadeas Kriz experimented with using Compose to drive an iOS set of Swift UI widgets for the droidcon 2022 app. Their takeaway: if you are looking to implement a Kotlin/Multiplatform app, Compose for iOS is worth considering.

Slides: Jetpack Compose @ Swile: last year retrospective

Romain Mouton and Benjamin Orsini delivered a presentation on what it took to migrate the Swile app to Compose UI, from creating the design system to interoperating with the existing View-based app.

How to remember the scroll position of LazyColumn built with Paging 3

Ferdinand Bada was running into problems with Paging-backed columns, where navigating away from and back to a column would reset the scroll position to the top. The underlying issue appears to be a classic “fixed, but not really” one, and Ferdinand walks us through a workaround.

Resource Roundup

100% pure code!

GitHub: maryamrzdh / compose-stepper

maryam memarzadeh created a stepper: a UI for showing the user a series of steps, with options for going forwards and backwards through those steps. The Stepper() handles rendering a row of step circles, with the caller supplying the names of the steps, optional colors, plus state information for where the user is within the step sequence. Learn more about it in this Medium post!

GitHub: mrhwsn / ComposeLock

Long-time Android users may remember using a pattern lock for their device, where a path among a grid of dots is used to represent the equivalent of a PIN. GitHub user mrhwsn created a ComposeLock() function that implements the same UI, with customizable grid size, dot and line rendering, and more.

GitHub: mateusz800 / Expandable-Compose-Calendar

Mateusz Budnik created a CalendarView() composable that can collapse to show a week or expand to show a month.

…And One More Thing

Compose is starting to show some cracks in its foundation.

The idea behind Compose was supposed to be simplicity: you “simply” declare what you want the UI to be based on the present state. Compose would arrange to:

  • Detect relevant state changes

  • Call your code to re-declare what the UI should be now

  • Figure out what changed between the previous UI and the new UI and make the necessary on-screen adjustments

You would just write nearly-ordinary functions to implement the code behind that second bullet. Using reactive data sources would “just work”, and Compose would be efficient when doing all of this.

And, at a high level, that is all still true. But, we are starting to see where the simplicity is not holding up:

  • Over-composing — doing unnecessary recompositions due to state changes — is a significant problem, dragging down performance. The good news is that the tooling is getting better for this, particularly in the Electric Eel and Flamingo editions of Android Studio. The bad news is that we have to start introducing artificial workarounds, like converting parameters into lambdas to reduce composition counts, as seen here and here.

  • Part of the theory behind composables, particularly the stock widgets, is that they are stateless. That is not always possible in practice. Last week’s warnings about TextField() stem from state management inside of TextField(), necessary because it needs to interact with external-to-Compose elements, such as the soft keyboard. As a result of this hidden state, we have to take steps to ensure that our composables are not wrecking that internal TextField() state management.

Neither of these things are show-stoppers. However, they do throw sand in the gears of Compose development. Worse, for teams who are currently considering whether or not to make the move to Compose, these sorts of problems cause more 🤔 or 🙃 than 😀.

In other words, some may feel that they are headed towards the trough of disillusionment.

If many more of these sorts of problems show up in the short term, Compose may be in for a rough go of it for a while. In the long run, it seems likely that Compose can be augmented to handle these two problems more naturally.

And, in the meantime… be sure to check your composition counts.