As I'm rewriting a 6 years old Watch Face project ...
# compose-wear
l
As I'm rewriting a 6 years old Watch Face project on top of AndroidX Wear Watchface, with the intent of publishing it on the Play Store this time, I'm wondering why we have a Compose backed API for Tiles in Glance, but we don't for WatchFaces. I think it'd be very helpful to have access to
remember { … }
,
State
, and other Compose facilities for interactive and animated Watch Faces. Is there a reason we don't have such an API? I'd think maybe there would be some performance concerns, or other potential issues, or maybe just bandwidth? I'm wondering about that because I am pondering about hacking around to use Compose to control what gets rendered on my Watch Face.
1
👍 1
y
I prototyped this, and think the idea could have legs. I think for a beginner, writing the watchface using compose for efficient updates based on state changes would work well.
But ultimately, I'd expect it would be hard to match an optimised watchface renderer writing directly to the canvas. And AndroidX Wear Watchface is the clean, new API for watchfaces, so it would be confusing to have multiple.
It wasn't complete, and was annoyingly always exactly 1 frame behind. Each render call updates the state, but the result was rendered to a Canvas(ImageBitmap) which was then displayed on the next frame.
The nice thing was that the Compose UI Canvas takes a lambda that writes to a DrawScope, so you can reuse logic between the two.
Also, you can't I couldn't avoid render calls when nothing has changed, so you still need to write the previous image on each frame.
That would seem the biggest win, if the app avoided most of the work, but compose made it do exactly the right amount of work based on what you had on screen - animations, minutes, second display and so on.
l
Interesting. Do you know what it was always 1 frame behind?
y
implementation choice. And it was just a hack/prototype.
Copy code
override fun render(
        canvas: android.graphics.Canvas,
        bounds: Rect,
        zonedDateTime: ZonedDateTime
    ) {
In the render method I did two things, a) draw the current state of the bitmap to avoid a slow render call. b) update the time (trimmed to seconds or minutes) in a MutableState.
That time update triggered my compose runtime (I couldn't use Compose UI, so it's more like the Mosiac/Molecule approach) to process state updates, but it was running in a separate coroutine scope, so effectively async.
I think ideally it would be run on every frame (call to render) and only update if something changed. But again this was just a prototype.
I have no plans to try to fix these issues, and it was basically just me exploring the same question you asked. But was a fun way to learn about writing a new compose runtime.
I think what would make it compelling is to end up with 2 shared aspects 1. Compose - remember, State, animations as you raise. 2. Reusable Canvas components, so using features from your App, including animated features and having the same development experience.
l
I see. It sounds like a Canvas-only or GLES-only Compose API could be helpful for watch faces. Especially for the latter, I think we could have a way to redraw only the needed pixels.
z
@Steve Bower [G] is this feature request being tracked already?
j
We have no plans to support Compose for Watch Faces - Watch Faces have an existing declarative approach with Watch Face Studio - https://developer.android.com/training/wearables/wfs
l
I doubt one can show minutes and animations like that with Watch Face Studio, it's a no-code thing, right?
j
If you find you can't get what you need with Watch Face studio you can drop down to the Watch Face and Complication Kotlin AndroidX Libraries we recently released. This is what Watch Face Studio uses under the covers
l
Yes, that's what these watch faces are doing, I just wish I could leverage remember, derivedStateOf and other Compose runtime facilities to avoid recomputing things that didn't change.
I'll keep using this approach for now (using AndroidX Wear Watchface, Canvas and plain Kotlin), optimizing manually where needed, and if it becomes too much hassle, I'll consider making my own compose runtime based watch face library.
👀 2
👍🏻 1