jetc.dev Newsletter Issue #78

Published: 2021-08-17

In this week’s issue, we look at limitations on how we can construct design systems in Compose UI. We also look at the history of the Button() API, how Square adapted Workflow to Compose, and how we might add a drop shadow to Text(). I point out some issues with debug builds and Compose performance. Plus, we see how a Google engineer uses Compose Material to build a shrine.

One Off the Stack, One Off the Slack

You’ve got questions. That’s understandable!

Creating Dashed Lines

Sometimes, we need a dashed or dotted line in a UI. There are multiple possible solutions to this problem, and this week’s highlighted Stack Overflow question explores two: drawing a dashed line on a Canvas() and creating a custom Shape() to apply to the background of something like a Box().

Principle of Least… Modifiability?

We are encouraged to create custom design systems as part of our work with Compose UI, wrapping existing composables in ones that implement our design requirements. However, you still wind up needing to offer flexibility with those composables, owing to how Compose is set up, as we see in this week’s highlighted Kotlinlang #compose Slack thread.

Composable Commentary

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

Medium: Pushing the Right Buttons in Jetpack Compose

Louis Pullen-Freilich, Matvei Malkov, and Preethi Srinivas of Google’s Compose UI team give us a tour of the history of the Button() composable. Its API changed a fair bit in its two-year history, and the team explains why they made those API changes, ranging from developer feedback to improving discoverability to dealing with underlying Compose changes.

Video: Building Shrine in Compose

Chris Sinco on Google’s Android tools team walks us through the use of Compose UI, building an implementation of the Shrine Material Design “study” and showing how Material Design gets expressed through composables.

Jetpack Compose Support in Workflow

Square created a library called Workflow that represents their foundation for constructing UIs in Android and iOS. Zach Klippenstein recounts Square’s approaches towards adopting Compose support in Workflow, as an in-depth analysis of how to take an opinionated architecture framework and adapt it to a similarly-opinionated UI framework.

Jetpack Compose - Text Shadows

Sam Edwards is back, looking at how to add a drop shadow effect to Text(). This is a stock option for <TextView> and is somewhat less straightforward to do in Compose UI. Sam illustrates a few approaches, one of which hopefully fits your needs.

Video: Migrating to Compose

Rivu Chakraborty delivered a droidcon Online presentation, looking at the work involved in migrating an existing app to Compose UI. This includes what changes you should make to your code before starting that migration, to make it easier to adopt Compose incrementally.

Medium: Recreating Google Podcasts’ Speed Selector in Jetpack Compose

Google Podcasts allows you to adjust the playback speed of the podcast that you are listening to, using a widget reminiscent of a SeekBar, but with custom styling and behavior. In this post, Francesc Vilarino Guell shows how to create a composable with the same basic look and feel, including handling the gestures, managing the animations, and snapping to specific values.

Medium: Accompanist — The First Chord

Google’s Accompanist family of libraries contain a wide range of composables and related code. Oleg Zhilo gives us a quick tour of what is all in those libraries and what their roles are.

Jetpack Compose Side-Effects — LaunchedEffect

Udit Verma has started a series of post looking at the ...Effect series of composables. The overall vision is that composables should be free from side effects, which means if you do need side-effects, you need to handle them with care. LaunchedEffect() lets you run coroutines with a scope tied to the current composable, and Udit shows how you can use it.

Resource Roundup

100% pure code!

GitHub: raipankaj / JetToast

Pankaj Rai created a small library to offer toast-style popups as composables, with several customization options (colors, background shapes, icons, animations, etc.).

GitHub: michaelgrigoryan25 / cobadge

Michael Grigoryan offers a similar composable library for badges (a.k.a., chips, tags), with support for varying shapes, colors, fonts, etc.

…And One More Thing

Compose is set of libraries. On the whole, this is a good thing, as this newsletter has covered in the past. Basically, we as developers get to control when we move to new versions of the library, and device manufacturers have less impact on the UI of our apps.

However, having the entire UI framework come from libraries has a cost: initial app performance.

Java/Kotlin source code get compiled to Dalvik bytecodes, which go in the DEX files of our apps. Eventually, the OS does work based on those bytecodes, in one of three ways:

  • Interpreted

  • Just-in-time (JIT) compiled, where the bytecodes are converted into CPU-specific instructions and cached in RAM for later reuse by this one process

  • Ahead-of-time (AOT) compiled, where the bytecodes are converted into CPU-specific instructions and are saved on disk for later reuse by future processes

In effect, framework classes, like TextView and ImageView, are AOT-compiled. Eventually, the DEX files in your apps will also have key portions be AOT-compiled. However, that does not happen immediately — Android needs your app to run for a while before it knows what is worth saving. In the beginning, your DEX files will be interpreted or JIT-compiled, and that will slow down execution.

As a result, a Compose UI app may run slower than will an equivalent app using the classic View system, at least until the AOT compilation process catches up.

Also, Compose relies a lot on R8 optimizations, and normally those are not run on debug builds, as R8 slows the build process. So, developers and others who rapidly churn through debug app builds will have even worse performance:

  • AOT compilation results get thrown out when the app gets replaced by a new build

  • If you are using debug builds, R8 optimizations are not performed

Developers may need to educate the QA team, product managers, and others about this and suggest that performance should be gauged based on release builds that have been installed for a while.

For more, see this Kotlinlang #compose Slack thread that depicts the difference between different app compilation states and their impacts.