Status Update
Comments
yu...@gmail.com <yu...@gmail.com> #2
Branch: androidx-master-dev
commit c60f33e229e31ab328ef6b59dab63b264954831c
Author: Alexandre Elias <aelias@google.com>
Date: Fri Jul 10 16:23:09 2020
Semantics no-op cleanups
Partly in response to lmr's broad code review, I did a pass of
superficial API/implementation cleanup. The main changes are:
- I changed each Boolean SemanticsProperty where false is equivalent to
not being present to take "Unit" instead. This is conceptually
clearer: it avoids questions like "can I cancel out a semantics from a
merged child by setting it to false?" Because "property = Unit" looks
weird, I also changed the style of these to "property()".
- I moved the Semantics id generator closer to where it's used, in
SemanticsModifierCore. I made it internal and an AtomicInt.
(Note that integer ids are heavily used in the Android
AccessibilityNodeInfo APIs so I can't simply remove them entirely.)
- I deleted dead code. Some examples include SemanticsHintOverrides,
a public API not connected to anything, and SemanticsPropertyKey
merge() open method which is never called. (In both cases I have
a different plan in mind for accessibility.)
Fixes: 145951226
Fixes: 145955412
Test: existing tests
Relnote: "Single-value semantics properties now use a calling style.
For example, 'semantics { hidden = true }' is now written as:
'semantics { hidden() }'."
Change-Id: Ic1afd12ea22c926babc9662f1804d80b33aa0cfc
M ui/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/LayoutNodeModifierBenchmark.kt
M ui/ui-core/api/0.1.0-dev15.txt
M ui/ui-core/api/current.txt
M ui/ui-core/api/public_plus_experimental_0.1.0-dev15.txt
M ui/ui-core/api/public_plus_experimental_current.txt
M ui/ui-core/api/restricted_0.1.0-dev15.txt
M ui/ui-core/api/restricted_current.txt
M ui/ui-core/src/androidAndroidTest/kotlin/androidx/ui/graphics/vector/VectorTest.kt
M ui/ui-core/src/androidAndroidTest/kotlin/androidx/ui/semantics/SemanticsTests.kt
M ui/ui-core/src/androidMain/kotlin/androidx/ui/core/AndroidActuals.kt
M ui/ui-core/src/androidMain/kotlin/androidx/ui/core/AndroidComposeView.kt
M ui/ui-core/src/androidMain/kotlin/androidx/ui/core/AndroidComposeViewAccessibilityDelegateCompat.kt
M ui/ui-core/src/androidMain/kotlin/androidx/ui/core/AndroidPopup.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/Expect.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsConfiguration.kt
D ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsHintOverrides.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsModifier.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsNode.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsOwner.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/core/semantics/SemanticsWrapper.kt
M ui/ui-core/src/commonMain/kotlin/androidx/ui/semantics/SemanticsProperties.kt
M ui/ui-foundation/api/0.1.0-dev15.txt
M ui/ui-foundation/api/current.txt
M ui/ui-foundation/api/public_plus_experimental_0.1.0-dev15.txt
M ui/ui-foundation/api/public_plus_experimental_current.txt
M ui/ui-foundation/api/restricted_0.1.0-dev15.txt
M ui/ui-foundation/api/restricted_current.txt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/Clickable.kt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/Dialog.kt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/Scroller.kt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/selection/Selectable.kt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/selection/Toggleable.kt
M ui/ui-foundation/src/main/java/androidx/ui/foundation/semantics/FoundationSemanticsProperties.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/ButtonTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/CardTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/CheckboxScreenshotTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/RadioButtonScreenshotTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/ScaffoldTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/SnackbarTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/SurfaceTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/ripple/RippleIndicationTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/textfield/TextFieldScreenshotTest.kt
M ui/ui-material/src/main/java/androidx/ui/material/AppBar.kt
M ui/ui-material/src/main/java/androidx/ui/material/TextFieldImpl.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/AssertsTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/CallSemanticsActionTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/ErrorMessagesTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/FindersTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/PrintToStringTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/ScrollToTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/TextActionsTest.kt
M ui/ui-test/src/main/java/androidx/ui/test/Actions.kt
M ui/ui-test/src/main/java/androidx/ui/test/Filters.kt
M ui/ui-text/api/0.1.0-dev15.txt
M ui/ui-text/api/current.txt
M ui/ui-text/api/public_plus_experimental_0.1.0-dev15.txt
M ui/ui-text/api/public_plus_experimental_current.txt
M ui/ui-text/api/restricted_0.1.0-dev15.txt
M ui/ui-text/api/restricted_current.txt
M ui/ui-text/src/commonMain/kotlin/androidx/ui/text/CoreTextField.kt
M ui/ui-text/src/commonMain/kotlin/androidx/ui/text/TextSemanticsProperties.kt
il...@google.com <il...@google.com> #3
I was able to reproduce this even on the latest alpha09.
I added the following code to the Screen
Composable to track the current Lifecycle
state:
val lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current
var lifecycleState by remember(lifecycleOwner) {
mutableStateOf(lifecycleOwner.lifecycle.currentState)
}
DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
lifecycleState = event.targetState
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose {
lifecycleOwner.lifecycle.removeObserver(observer)
}
}
Text(text = "$lifecycleState", style = MaterialTheme.typography.h4)
After re-selection, it shows that the Lifecycle does not go above CREATED
.
il...@google.com <il...@google.com> #4
We need to ensure that singleTop operations (like this) give us a NavBackStackEntry
that is not .equals()
to the old entry. This ensures that Compose won't skip updating the LocalLifecycleOwner.current
value in this case.
This has a couple of (internal only) implications to make sure that our internal state is consistent:
- We need to fix
NavController
's to ensure that the new entry is added to our child/parent Lifecycle tracking mapscall to navigator.onLaunchSingleTop()
- Ensure that we don't clear ViewModels associated with singleTop operations (i.e., validate that the same entry ID isn't on the back stack)
- Update the
to update the value as a single atomic operation (which is now possible since the entries aren'tdefault implementation of NavigatorState.onLaunchSingleTop
.equals()
to one another) - Look at how
TestNavigatorState
treats reference equality to make sure it still clears/saves state properly
ap...@google.com <ap...@google.com> #5
Branch: androidx-main
commit 8ed73a2b43c94f0a1deaf12ab13e5161c2fab5cf
Author: Jeremy Woods <jbwoods@google.com>
Date: Tue Sep 28 18:09:48 2021
Modify NavBackStackEntry equality
Including the Lifecycle and SavedStateRegistry in the NavBackStackEntry
equals and hashcode functions. This will fix our issues in compose where
different instances of NavBackStackEntry were considered the same and we
were not recomposing properly.
This change always required the following:
Ensuring that ViewModels are not cleared during singleTop operations
Making sure markTransitionComplete clears all entries with the same ID
Ensure when NavController calls onSingleTop we update the links between
child and parents
We also made onLaunchSingleTop in NavigatorState a single atomic
operation to remove the old entry and add the new one.
RelNote: "NavBackStackEntries now with different Lifecycles are not
longer considered equal. This means NavHost will properly recompose all
destinations when doing navigation with singleTop and when reselecting
bottom menu items."
Bug: 196997433
Test: Added tests
Change-Id: I1b3510b238d3c4e6ed5cc86a6fddf795bd9acb02
M navigation/navigation-common/src/main/java/androidx/navigation/NavigatorState.kt
M navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryTest.kt
M navigation/navigation-testing/src/androidTest/java/androidx/navigation/testing/TestNavigatorStateTest.kt
M navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.kt
M navigation/navigation-testing/src/main/java/androidx/navigation/testing/TestNavigatorState.kt
M navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavBackStackEntryLifecycleTest.kt
M navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt
jb...@google.com <jb...@google.com> #6
This has been fixed internally and will be available in the next Navigation release.
yu...@gmail.com <yu...@gmail.com> #7
That's great! Is there Snapshot build number I can try before the release to test/use it?
yu...@gmail.com <yu...@gmail.com> #8
Looks like
yu...@gmail.com <yu...@gmail.com> #9
I tried build #7796270 and looks like the bug is gone. Thanks!
Description
Component used: Navigation Version used: Snapshot #7634339 or 2.4.0-alpha07 Devices/Android versions reproduced on: Pixel 4a
This issue is related to another fixed issue: https://issuetracker.google.com/issues/194925622
2.4.0-alpha05 introduced a bug where tab reselection causes empty screens, unless the current screen is the
startDestination
of the root graph.The issue was fixed in Snapshot #7634339 , but it introduced another bug:
Flows collected in compose screens via
rememberFlowWithLifecycle(flow).collectAsState(initial)
complete early on tab reselection, like in the original issue. AboutrememberFlowWithLifecycle
Attaching the minimal sample that shows the problem and a video.
In sample view model, there is a simple flow that emits text in some interval.
In 2.4.0-alpha04 - Collecting flows directly via collectAsState or via rememberFlowWithLifecycle works as expected (interval Flow doesn't complete until the user leaves the screen)
In 2.4.0-alpha05-06 - Screen becomes empty on tab reselection
In Snapshot #7634339 / 2.4.0-alpha07:
rememberFlowWithLifecycle