Philip Dukhov
12/19/2021, 3:05 AM@Composable
function, it shows the following:
@[ERROR : Composable]
public fun Screen(): Unit
I didn't find any related errors in the gradle sync output, also filtering idea.log
on the word "compose"
didn't show anything interesting. What could be causing this problem? Is there a place where I can look for related logs?elye
12/19/2021, 2:31 PMrememberSaveable
) seems to cover Both onConfiguration and State Restoration.Rick Regan
12/20/2021, 2:23 AMRememberSaveable
and explicit writes to the bundle in onSaveInstanceState()
) and it restores except sometimes after long stretches in the background (8-12 hours) on my real device. (Some other apps on my device appear to behave similarly, and others don’t, which makes me more curious.)iamthevoid
12/20/2021, 8:38 AMAnkit Shah
12/20/2021, 12:21 PMMatti MK
12/20/2021, 12:25 PMrememberInfiniteTransition()
as shown below which works nicely, but is not state based.
I’m wondering which animation I should go with to have a repeatable
animation with RepeatMode.Reverse
and have it be state-based? I looked into repeatable
(https://developer.android.com/jetpack/compose/animation#repeatable), but I still have to provide an iteration count, which I do not know beforehand. Thanks 👍
rememberInfiniteTransition().animateValue(
initialValue = 60,
targetValue = 80,
typeConverter = Int.Companion.VectorConverter,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = ANIMATION_TIME, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
)
)
Tim Malseed
12/20/2021, 11:10 PMManojna Chintapalli
12/20/2021, 11:50 PMpablisco
12/21/2021, 1:57 AMMatti MK
12/21/2021, 6:16 AMRow
with horizontalScroll
. All the elements of the Row
have a Text
that can be of any width. I’d like to make all the elements of the Row to take up the same width as the largest element. Any tips on how to go about this? In the ConstraintLayout world something like this could be perhaps achieved with Barrier
iamthevoid
12/21/2021, 7:59 AMgestureEnabled
is what am i looking for, but looks like gestureEnabled
disable gestures inside BottomDrawer content too. Is there way to disable gestures for bottom drawer, but leave it for its content?Ankit Shah
12/21/2021, 11:07 AMFlorian Walther (live streaming)
12/21/2021, 12:11 PMobserveAsState
take care of that?
https://stackoverflow.com/a/66837741Florian Walther (live streaming)
12/21/2021, 1:30 PMBrian Donovan
12/21/2021, 3:27 PMTim Malseed
12/21/2021, 10:40 PMTim Malseed
12/22/2021, 6:48 AM@Test
fun myTest() {
composeTestRule.activity.runOnUiThread {
val backPressedDispatcher = (composeTestRule.activity as OnBackPressedDispatcherOwner).onBackPressedDispatcher
backPressedDispatcher.onBackPressed()
}
assertEquals(composeTestRule.activityRule.scenario.state, Lifecycle.State.DESTROYED)
Stylianos Gakis
12/22/2021, 6:54 AMColumn {
Item()
Spacer(Modifier.height(16.dp))
OtherItem()
}
B:
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
Item()
OtherItem()
}
I’d love to hear arguments/opinions too if someone feels like they have strong opinions about either way.Stylianos Gakis
12/22/2021, 8:01 AMMonetaryAmount
from org.javamoney:moneta
in compose @Preview functions.
It seems like the JDKCurrencyProvider
isn’t yet created for the previews, therefore it fails fetching the currency. Anyone had the same issue before that can provide some workaround?
It would also be nice to be able to run a debugger on my code for the preview in order to see what fails exactly potentially? This is probably too hard though, considering I do not understand under which special rules the previews run exactly.Vitaliy Zarubin
12/22/2021, 8:42 AMAnastasia Rozovskaya
12/22/2021, 11:49 AMjava.lang.IllegalStateException: LayoutNode should be attached to an owner at androidx.compose.ui.node.LayoutNodeKt.requireOwner(LayoutNode.kt:1372)
while clicking on a particular list item (2nd item actually). The set up is as follows: Fragment with recyclerview, where each item is a compose card. Compose version is 1.0.5. Any help would be appreciated.dimsuz
12/22/2021, 1:43 PMBox {
// 500dp intrinsic width image
Image(
painter = painterResource(R.drawable_image_500x56),
contentScale = FillHeight,
alignment = TopStart)
Text("hello")
}
Currently this box has size 500.dp
due to `Image`'s intrinsic width. But I want this box to have width of the Text
and for Image
to be painted and horizontally clipped on the right. Is this possible with default layouts?Benjamin Deroche
12/22/2021, 4:11 PMzIndex
do nothing in a LazyVerticalGrid
? I've implemented a drag and drop feature that work perfectly well in LazyColumn
and LazyRow
, but in the LazyVerticalGrid
, the zIndex
I apply to the dragged element (to always show it on top) have no effect. The dragged element is always shown behind the next elements in the list and above the previous elements in the list. I also tried another "static" implementation using Row
and Column
but it have the same problem.Yingding Wang
12/22/2021, 7:04 PMmattinger
12/22/2021, 7:33 PMNat Strangerweather
12/22/2021, 10:01 PMSher Sanginov
12/23/2021, 1:10 AMandroidx
UI testing with compose in my project.
Any idea what may be wrong? I tried to play with dependencies but no success.
java.lang.RuntimeException: Unable to resolve activity for: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.myapp.debug.test/androidx.activity.ComponentActivity }
at androidx.test.core.app.InstrumentationActivityInvoker.startActivity(InstrumentationActivityInvoker.java:387)
...
Full stacktrace in thread.uptoyou
12/23/2021, 12:09 PMhttps://www.youtube.com/watch?v=Z3KhZzAhCIY▾
Lukasz Kalnik
12/23/2021, 12:55 PMRow
containing a free Text
element and two `TextButton`s. I want the Text
be aligned by baseline with the `TextButton`s:
Row(modifier = Modifier.alignByBaseline()) {
Text(
text = "Geräte",
style = MaterialTheme.typography.h6
)
TextButton(
onClick = { /*TODO*/ },
) {
Text(
text = "Alle an",
style = MaterialTheme.typography.h6,
)
}
TextButton(onClick = { /*TODO*/ }) {
Text(
text = "Alle aus",
style = MaterialTheme.typography.h6,
)
}
}
Stylianos Gakis
12/23/2021, 2:49 PMremember
, mutableStateOf
, derivedStateOf
where all of them seem like they’d do the same thing-ish but with slight differences and potential premature-optimizations by me? More on Thread 🧵Stylianos Gakis
12/23/2021, 2:49 PMremember
, mutableStateOf
, derivedStateOf
where all of them seem like they’d do the same thing-ish but with slight differences and potential premature-optimizations by me? More on Thread 🧵submittedAt: Instant
and I want to show on the UI the time passed since then. I can now do this in all these three ways and it all works.
@Composable
fun MyComposable(submittedAt: Instant) {
val now by currentTimeAsState(updateIntervalInSeconds = 1L)
val someText1 = remember(submittedAt, now) {
getRelativeTimeSpanString(submittedAt, now)
}
val someText2 by remember(submittedAt, now) {
mutableStateOf(getRelativeTimeSpanString(submittedAt, now))
}
val someText3 = remember(submittedAt, now) {
mutableStateOf(getRelativeTimeSpanString(submittedAt, now))
}
val someText4 by remember {
derivedStateOf { getRelativeTimeSpanString(submittedAt, now) }
}
LogCompositions("RECOMPOSING!")
Text(text = someTextX) // on someText3 I used `someText3.value` instead
}
As I understand for options #:
1. A simple remember with the keys that getRelativeTimeSpanString
relies on so that when either of them change the getRelativeTimeSpanString
function is called again and updates someText1
. This will be recalculated every time now
changes which in this case is every second (could be faster too in some other use case) therefore we get a bunch of useless recompositions. The LogCompositions
functions confirms that.
2. I am not even sure if I was expecting a difference here, but I didn’t get one anyway. I am assuming I would define something like this if it were a var
that was also mutated inside this composable, not even sure how different this is from #1.
3. Same thing, unsurprisingly
4. This should read submittedAt
and now
from the snapshot automatically and only update someText4
when the result of getRelativeTimeSpanString
is different from the previous result, therefore acting as some sort of conflate method that flows have, therefore doing recompositions only when it’s needed? LogCompositions
does confirm that recompositions only happen when the text changes in the end. Bonus points for not even having to be explicit about the keys since derivedStateOf
has some internal check as I understand.
So in conclusion, should we always go for option #4 then? Since derivedStateOf
isn’t free either, is this internal check that derivedStateOf
does so expensive that we shouldn’t always do it? How would we make an informed decision on this, I am unsure.
Note that even on options #1-#3 MyComposable
did not recompose when the someText
was read inside another composable down lower that was not inline, therefore it had its own “smaller” recompose scope. But since it only work in that case it feels like a thing that I don’t want to think about in general, and most of the time this isn’t even the case.@Composable
fun currentTimeAsState(
updateIntervalInSeconds: Long = 1L,
clock: Clock = Clock.systemUTC(),
): State<Instant> {
return produceState(initialValue = Instant.now(clock)) {
while (isActive) {
delay(updateIntervalInSeconds * 1_000)
value = Instant.now(clock)
}
}
}
fun getRelativeTimeSpanString(
from: Instant,
to: Instant = Instant.now(),
): String {
return DateUtils.getRelativeTimeSpanString(
from.toEpochMilli(),
to.toEpochMilli(),
DateUtils.SECOND_IN_MILLIS
).toString()
}
// Taken from <https://www.jetpackcompose.app/articles/donut-hole-skipping-in-jetpack-compose>
@Composable
inline fun LogCompositions(msg: String) {
if (BuildConfig.DEBUG) {
val ref = remember { Ref(0) }
SideEffect { ref.value++ }
d { "Compositions: $msg ${ref.value}" }
}
}
class Ref(var value: Int)
Albert Chang
12/23/2021, 3:32 PMderivedStateOf
when either:
1. the calculation is expensive
2. the derived state changes less frequently than the original state(s) changes
Otherwise you can just use simple calculation without remember
.
Since your case falls into category 2, I would say pattern 4 is the best.
Pattern 2 and 3 are meaningless as you are never changing the value of the mutable state.Stylianos Gakis
12/23/2021, 3:44 PMremember
though? With this wording alone, I’d first think of using a simple remember if all I knew about my use case is that it’s “expensive”
This does fall into the point #2 you made though, it’s just that it’s not what first comes to my mind when dealing with such cases. I guess it’s a pattern that I’ll have to learn to spot by intuition? It’s definitely non-obvious in my head still.Casey Brooks
12/23/2021, 4:22 PMremember { }
is intended to be used for values that need to be kept constant across recompositions. In this case, anytime now
changes, you want to recompute the elapsed time and thus do not want it remembered across recompositions. So that right there should be a signal that #1-3 are not a good fit, and derivedStateOf { }
is what you want to use, or else just compute it directly if it's a fast calculation. derivedStateOf { }
has internal mechanisms for detecting when it is reading State
values, and only changes itself when those values themselves are changed. It's less about being tracked across recomposition, and more about optimizing chains of State
variables that depend on each other.
One huge difference between remember { }
and derivedStateOf { }
is that the former is @Composable
while the latter is not. You can stick a call to derivedStateOf { }
in other layers of your application (not just the @Composable
layer), for example, a ViewModel that makes computations based on State
variables. It's probably not the best practice to do that often (it's still a Compose API and you generally don't want to couple your other layers to Compose), but in some specific scenarios it may be an invaluable tool.mutableStateOf()
doesn't work without remember { }
. It can only track its changes internally if the State
itself is remembered across compositions. You could also hold those State
objects in some other class that lives outside of Compose, such as your ViewModel, and not need the call to remember { }
since the ViewModel keeps the state alive across recomposition.
Also, State
objects in general can always be assigned to variables by delegate, so the differences between #2 and #3 are purely syntactic, but do the exact same thing. The implementation of the by State<T>
delegate it literally just an inlined call to .value
, so there is no runtime difference between one way or the otherAlex Vanyo
12/23/2021, 6:51 PMderviedStateOf
can only track changes to State
objects that it reads in its block.
now
is one such state (due to the delegate), but submittedAt
is not: it’s a plain value passed in as an argument.
Because of that, derivedStateOf
will continue to use the same, stale submittedAt
value even if MyComposable
recompose with a different submittedAt
value because remember
has no keys.
There are two ways to get correct behavior from this:
Adding a key to remember
for `submittedAt`:
val someText4 by remember(submittedAt) {
derivedStateOf { getRelativeTimeSpanString(submittedAt, now) }
}
Using `rememberUpdatedState`:
val currentSubmittedAt by rememberUpdatedState(submittedAt)
val someText4 by remember {
derivedStateOf { getRelativeTimeSpanString(currentSubmittedAt, now) }
}
derivedStateOf
like a caching tool: It can be very useful in some situations, but you then also need to be extremely careful with how that caching gets invalidated.
In most cases you’d probably be better off just doing the calculation directly.Stylianos Gakis
12/23/2021, 8:30 PMsubmittedAt
was passed into this function as a State<Instant>
instead of an Instant
?Alex Vanyo
12/23/2021, 9:01 PMderivedStateOf
will capture the old State<Instant>
instance. If you just changed the value of the same State<Instant>
instance, it might work, but if MyComposable
got recomposed with a different State<Instant>
instance passed into it, the derivedStateOf
will still be stuck listening for changes on the old one.
(separately, having [Mutable]State<Instant>
as a parameter is frowned upon: https://kotlinlang.slack.com/archives/CJLTWPH7S/p1637855772048800?thread_ts=1637854750.046000&cid=CJLTWPH7S)Stylianos Gakis
12/24/2021, 9:02 AM() -> T
too. What's the use case for that over just T
?
Interestingly, in this case if I had () -> T
it's more likely that I'd intuitively use updatedState
since I'm used to seeing it being used with lamdas and it makes sense that it'd be stale inside derivedStateOf
but now I see that this can be true for normal variables too 🤔Alex Vanyo
01/04/2022, 8:08 PMState<T>
, for calling State<T>.value
at some later point in time, but it’s preferred to just pass in the direct () -> T
lambda for that case.
And yup, I was in the same boat of thinking rememberUpdatedState
was just for lambdas, but it’s a more general tool to convert a parameter for a @Composable
back into a State<T>
that can be observed with deferred reads like any other state further downstream.
If you wanted to do that manually without rememberUpdatedState
, I bet you’d get pretty close to the exact implementation of it: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/[…]ate.kt;l=295-297;drc=44c23a7214a34d089ac218acb9460a66e5405c12Stylianos Gakis
01/05/2022, 4:20 AM