Alex Vanyo

Alex Vanyo

@vanyo.dev

Android Software Engineer Helping build adaptive Compose everywhere!

623 followers104 following126 posts

Alex Vanyo reposted

Jetpack Compose 1.12 has been released! So many new goodies to look at: ๐ŸŒ… Mesh Gradient support - along with support inside Android Studio for editing โœŒ๐Ÿป Interactive Two-Stage Transitions ๐Ÿ’ฌ Many text features such as editable text formatting android-developers.googleblog.com/2026/08/jetp...

android-developers.googleblog.comWhat's new in the Jetpack Compose August '26 releaseNews and insights on the Android platform, developer tools, and events.

Alex Vanyo reposted

๐Ÿ‘€ Want to see a preview of what's coming up in #JetpackCompose? We heard you that debugging shared elements is tricky. In 1.11.0-alpha03, a new composable LookaheadAnimationVisualDebugging was added. Wrap your SharedTransitionLayout to add visual cues to track down those hard to debug issues. ๐Ÿ›โคต๏ธ

I've converted my side project to Navigation 3 (or at least, a similar close fork of Navigation 3), which you can try out on the web here! alex.vanyo.dev/composelife Two more complex scene ideas I've been playing around with: A SceneStrategy wrapping another SceneStrategy, and derived entry lists.

View full thread

One technique to solve this is to not have the detail in the underlying backstack state at first, and derive an entry list with a "transient" detail entry at larger window sizes. Only when you actually navigate to that entry does the entry get "realized" and get added to the underlying backstack.

That way, resizing the window smaller will remain on the list until you've directly navigated to the detail, and then resizing smaller will remain on the detail. No need for an empty detail placeholder:

I've converted my side project to Navigation 3 (or at least, a similar close fork of Navigation 3), which you can try out on the web here! alex.vanyo.dev/composelife Two more complex scene ideas I've been playing around with: A SceneStrategy wrapping another SceneStrategy, and derived entry lists.

Idea 1: I have a list-detail setup for my settings, but if there's even more space available, I want the entire list-detail setup to be in a dialog. I can do that by creating a custom DialogSceneStrategy that wraps my other scene strategies, and having the DialogScene wrap an arbitrary Scene:

Idea 2: Because Navigation 3 allows hoisting the backstack state arbitrarily, you can give a backstack to the NavDisplay that is derived from some other state. Another tricky list-detail case is when you want the first detail visible initially, but only if there's enough space for it.

Alex Vanyo reposted

The reason I did catch this later was a failing StrictMode ThreadPolicy. But a lint rule warning against with(CoroutineContext) seems like it'd be nice to have.

The recording from my talk on how to handle configuration changes in Compose at #dcnyc25 is out! Hopefully this helps explain what android:configChanges is responsible for in #AndroidDev and why it's important to know what promises you make when setting it. www.youtube.com/watch?v=K5-9...

youtube.comHandling configuration changes in Compose - Alex Vanyo | droidcon New York 2025YouTube video by droidcon & fluttercon
Alex Vanyo@vanyo.dev

It was great to see both familiar faces and new ones at #dcnyc25 last week - especially to see how everyone's figuring out what #AndroidDev will look like with the new tools are moving at a blistering speed. The slides for my talk are available here: alex.vanyo.dev/talks/configurationchanges

A response to the section on "How Can I Determine the Size and Position of Descendants of Peers?" Using onGloballyPositioned (or onSizeChanged, or similar modifiers) like this is a quick way to get yourself into trouble with layouts that take multiple frames to resolve that can flash or look janky.

Mark Murphy@commonsware.com

I just sent out jetc.dev Newsletter Issue #273! Android Makers! @eevis.codes on accessibility focus *and* keyboard focus! FABs and FAMs! PWAs! jetc.dev/issues/273 #JetpackCompose #AndroidDev

View full thread

I'm curious how prevalent the onGloballyPositioned pattern is and why - does it feel like the best way to accomplish more custom layout behavior? Is it the easiest thing to get something working close enough? Are there missing tools that would make it less likely you'd use onGloballyPositioned?

A response to the section on "How Can I Determine the Size and Position of Descendants of Peers?" Using onGloballyPositioned (or onSizeChanged, or similar modifiers) like this is a quick way to get yourself into trouble with layouts that take multiple frames to resolve that can flash or look janky.

Mark Murphy@commonsware.com

I just sent out jetc.dev Newsletter Issue #273! Android Makers! @eevis.codes on accessibility focus *and* keyboard focus! FABs and FAMs! PWAs! jetc.dev/issues/273 #JetpackCompose #AndroidDev

View full thread

This can also wreck havoc on animations - maybe they can cover up some of the jankiness, but animations need to have a consistent view of the layout as it animates at each point in time. Shared element transitions don't really work if the shared element disappears completely for a frame.

Unfortunately there's not really a one-size-fits-all solution for every case, but don't be afraid of a custom layout - if you're already doing some math to change the layout of something based on something else, you're about 80% of the way there to writing a custom layout.

A response to the section on "How Can I Determine the Size and Position of Descendants of Peers?" Using onGloballyPositioned (or onSizeChanged, or similar modifiers) like this is a quick way to get yourself into trouble with layouts that take multiple frames to resolve that can flash or look janky.

Mark Murphy@commonsware.com

I just sent out jetc.dev Newsletter Issue #273! Android Makers! @eevis.codes on accessibility focus *and* keyboard focus! FABs and FAMs! PWAs! jetc.dev/issues/273 #JetpackCompose #AndroidDev

When you have composition being driven by information that you can only get in a later phase, like measurement, layout or drawing, the first composition can't be correct! This means that the first frame might be blank, or components might jump around as you get more info.

Nesting this approach makes the situation even worse - each time you put a calculation like this inside another one, it adds an additional frame required to resolve the whole layout.

View full thread

Some are a lot trickier to handle directly - and it's pretty easy to write code that works assuming that recreation happens. Opting out of recreation is also a promise that new code works properly with updating in-place when the configuration changes.

And to reiterate again: configuration changes will happen, and you have to react to them. For each type of configuration change, your options are: - using Activity recreation, and properly preserving state through it - opting-out of recreation, and updating everything in place

View full thread

TL;DR: if you know the promise you are making, you can opt-out of Activity recreation via android:configChanges. The golden rule to do so properly in Compose is to have everything using configuration depend on a snapshot-state-backed source for it, like LocalConfiguration and LocalResources.

It's also not all or nothing! Most Android apps can probably opt-out of recreation for some configuration changes that don't need apps to do much (if anything), like keyboard, touchscreen, and colorMode. That'd immediately solve a whole class of bugs for physical keyboards and connected displays.

I'm excited to be speaking at #DroidconNYC next Thursday, hope to see you there! I'll be covering how to handle configuration changes in Compose, and specifically trying to answer the question of what you should put in android:configChanges and - probably more importantly - why. #AndroidDev

Thinking about configuration changes isn't optional. Imagine a website trying to prevent the browser window from being resized or breaking when it does. Android apps can't disable configuration changes and need to react to them correctly without losing state using the tools available.

Jorge Castillo@jorgecastillo.dev

If you could whisper one Android dev secret to every junior starting today, what would it be? Quote tweet this. Letโ€™s build the Android wisdom tree ๐ŸŒฑ

Hopefully you have a bunch of ideas to improve your apps from the first day of #GoogleIO Day 2 starts soon, be sure to tune in to learn about what's new in developer tools and my favorite topic, why and how to build adaptive! #AndroidDev

Scenes! If there's only one concept to call out for Navigation 3, it's scenes. The abstraction layer allows showing multiple panes at a time, and in different ways. It's the integration hook that integrates Navigation3 with ListDetailPaneScaffold in a flexible, satisfying way.

Ian Lake@ianlake.bsky.social

Today, we've released a brand new Jetpack library - Navigation3! A pure Compose, state based navigation library: android-developers.googleblog.com/2025/05/anno...

That's not the only concept of course - all of that builds on a backstack driven by Compose state, directly under the developers control.

runComposeUiTest has a nice change in #JetpackCompose 1.9.0-alpha01 - the test body block now suspends! So you no longer have to do a nested runComposeUiTest { runTest { /* suspending test code */ } }, which could be funky since runComposeUiTest had an internal runTest before that wasn't exposed.

A small but extremely useful foundational API added in #JetpackCompose 1.8: LocalWindowInfo.current.containerSize It's the best way to get the size of the window, which should form the basis for any breakpoint logic for top-level layouts like window size classes. #AndroidDev

Alex Vanyo reposted

๐Ÿš€ Big news for Android devs using Jetpack Compose! Media3 just dropped version 1.6.0, and it includes a brand new artifact: media3-ui-compose! Finally, seamless and customizable video playback directly in your Compose apps. ๐ŸŽฌ #AndroidDev #JetpackCompose #Media3

Alex Vanyo reposted

Replying to @jorgecastillo.dev

So the idea is with strong skipping, === is an extremely fast check. Imagine you have a lazy list and an array with a couple of hundred items, 3 on screen. Depending on the cost of equals, it's faster to let that higher level recomposition happen with ===.

UI that isn't tested is UI that can break. There are Compose techniques for each part of testing - quick verification when iterating, and automating both visual tests and behavior tests. And coming in Compose 1.8, don't miss the new DeviceConfigurationOverride.WindowInsets for testing insets!

Simona Milanovic@anomiss.bsky.social

โœจ New Delightful Compose video is out! โœจ @vanyo.dev has some great tips on how to keep your UI delightful long term by testing it! Previews, screenshot testing, DeviceConfigurationOverride and other helpful tools are covered here: www.youtube.com/watch?v=Y9GW...

Alex Vanyo reposted

A ๐Ÿงต announcement: With the Jetpack Compose 1.8. beta01 release, you may notice that a significant number of APIs that were previously experimental, have been graduated to stable.

After figuring out how to make the coordinates work, it's so satisfying to use a live-updating drag and drop that previews where the dropped content will go.

Some quirks: writing automated tests for this was hard since the drag and drop is done at the system level. I found a super hacky way to do so by interleaving normal Compose testing utilities and raw MotionEvents injected with UiAutomation.

Also Coil right now doesn't work well with the default drag decoration for Modifier.dragAndDropSource, which is unfortunate since dragging images seems like use case #1 for drag and drop. I think I have a decent workaround though: github.com/coil-kt/coil...

At minimum, you have a screen coordinate space (which is almost never what you want to use), a window coordinate space, and a Compose root coordinate space. Each of those can be measured in dps or pixels, and sometimes it matters if those pixels are integers or floats.

And then every single node has its own local coordinate space, after layouts and padding and scrolling and translations are each applied. Keeping track of what coordinate system you want to be working in is tricky when you start having complicated interactions that move across boundaries.