Status Update
Comments
jo...@jossiwolf.de <jo...@jossiwolf.de> #2
Branch: androidx-master-dev
commit fcf76b3241844f18106d6e850004952046d4bfb6
Author: Leland Richardson <lelandr@google.com>
Date: Wed May 13 16:58:59 2020
Deprecate @Model
Relnote: “
@Model annotation is now deprecated. Use state and mutableStateOf as alternatives. This deprecation decision was reached after much careful discussion.
Justification
=============
Rationale includes but is not limited to:
- Reduces API surface area and concepts we need to teach
- More closely aligns with other comparable toolkits (Swift UI, React, Flutter)
- Reversible decision. We can always bring @Model back later.
- Removes corner-case usage and difficult to answer questions about configuring @Model as things we need to handle
- @Model data classes, equals, hashcode, etc.
- How do I have some properties “observed” and others not?
- How do I specify structural vs. referential equality to be used in observation?
- Reduces “magic” in the system. Would reduce the likelihood of someone assuming system was smarter than it is (ie, it knowing how to diff a list)
- Makes the granularity of observation more intuitive.
- Improves refactorability from variable -> property on class
- Potentially opens up possibilities to do hand-crafted State-specific optimizations
- More closely aligns with the rest of the ecosystem and reduces ambiguity towards immutable or us “embracing mutable state”
Migration Notes
===============
Almost all existing usages of @Model are fairly trivially transformed in one of two ways. The example below has a @Model class with two properties just for the sake of example, and has it being used in a composable.
```
@Model class Position(
var x: Int,
var y: Int
)
@Composable fun Example() {
var p = remember { Position(0, 0) }
PositionChanger(
position=p,
onXChange={ p.x = it }
onYChange={ p.y = it }
)
}
```
Alternative 1: Use State<OriginalClass> and create copies.
----------------------------------------------------------
This approach is made easier with Kotlin’s data classes. Essentially, make all previously `var` properties into `val` properties of a data class, and then use `state` instead of `remember`, and assign the state value to cloned copies of the original using the data class `copy(...)` convenience method.
It’s important to note that this approach only works when the only mutations to that class were done in the same scope that the `State` instance is created. If the class is internally mutating itself outside of the scope of usage, and you are relying on the observation of that, then the next approach is the one you will want to use.
```
data class Position(
val x: Int,
val y: Int
)
@Composable fun Example() {
var p by state { Position(0, 0) }
PositionChanger(
position=p,
onXChange={ p = p.copy(x=it) }
onYChange={ p = p.copy(y=it) }
)
}
```
Alternative 2: Use mutableStateOf and property delegates
--------------------------------------------------------
This approach is made easier with Kotlin’s property delegates and the `mutableStateOf` API which allows you to create MutableState instances outside of composition. Essentially, replace all `var` properties of the original class with `var` properties with `mutableStateOf` as their property delegate. This has the advantage that the usage of the class will not change at all, only the internal implementation of it. The behavior is not completely identical to the original example though, as each property is now observed/subscribed to individually, so the recompositions you see after this refactor could be more narrow (a good thing).
```
class Position(x: Int, y: Int) {
var x by mutableStateOf(x)
var y by mutableStateOf(y)
}
// source of Example is identical to original
@Composable fun Example() {
var p = remember { Position(0, 0) }
PositionChanger(
position=p,
onXChange={ p.x = it }
onYChange={ p.y = it }
)
}
```
“
Bug: 156546430
Bug: 152993135
Bug: 152050010
Bug: 148866188
Bug: 148422703
Bug: 148394427
Bug: 146362815
Bug: 146342522
Bug: 143413369
Bug: 135715219
Bug: 126418732
Bug: 147088098
Bug: 143263925
Bug: 139653744
Change-Id: I409e8c158841eae1dd548b33f1ec80bb609cba31
M compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/frames/FrameDiagnosticTests.kt
M compose/compose-runtime/api/0.1.0-dev12.txt
M compose/compose-runtime/api/current.txt
M compose/compose-runtime/api/public_plus_experimental_0.1.0-dev12.txt
M compose/compose-runtime/api/public_plus_experimental_current.txt
M compose/compose-runtime/api/restricted_0.1.0-dev12.txt
M compose/compose-runtime/api/restricted_current.txt
M compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/ComposeBenchmark.kt
M compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/SiblingBenchmark.kt
M compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/dbmonster/DbMonster.kt
M compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/realworld4/RealWorld4_DataModels.kt
M compose/compose-runtime/samples/src/main/java/androidx/compose/samples/ModelSamples.kt
M compose/compose-runtime/src/commonMain/kotlin/androidx/compose/FrameManager.kt
M compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Model.kt
M compose/compose-runtime/src/commonMain/kotlin/androidx/compose/MutableState.kt
M compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Observe.kt
M compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recompose.kt
M compose/compose-runtime/src/commonMain/kotlin/androidx/compose/StableMarker.kt
M ui/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/ModelObserverBenchmark.kt
M ui/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/RadioGroupBenchmark.kt
M ui/integration-tests/demos/src/main/java/androidx/ui/demos/DemoColorPalette.kt
M ui/integration-tests/src/main/java/androidx/ui/integration/test/foundation/RectsInColumnSharedModelTestCase.kt
M ui/ui-android-view/integration-tests/android-view-demos/src/main/java/androidx/ui/androidview/demos/WebComponentActivity.kt
M ui/ui-animation/src/main/java/androidx/ui/animation/AnimatedValueEffects.kt
M ui/ui-animation/src/main/java/androidx/ui/animation/Transition.kt
M ui/ui-core/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
M ui/ui-core/src/androidTest/java/androidx/ui/core/test/AndroidViewCompatTest.kt
M ui/ui-core/src/androidTest/java/androidx/ui/core/test/ClipTest.kt
M ui/ui-core/src/androidTest/java/androidx/ui/core/test/DrawShadowTest.kt
M ui/ui-core/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt
M ui/ui-core/src/androidTest/java/androidx/ui/core/test/OpacityTest.kt
D ui/ui-core/src/androidTest/java/androidx/ui/core/test/ValueModel.kt
M ui/ui-core/src/androidTest/java/androidx/ui/core/test/WithConstraintsTest.kt
M ui/ui-core/src/androidTest/java/androidx/ui/res/ResourcesTest.kt
M ui/ui-core/src/androidTest/java/androidx/ui/semantics/SemanticsTests.kt
M ui/ui-core/src/main/java/androidx/ui/core/ModelObserver.kt
M ui/ui-core/src/main/java/androidx/ui/res/Resources.kt
M ui/ui-core/src/test/java/androidx/ui/core/selection/SelectionManagerDragTest.kt
M ui/ui-core/src/test/java/androidx/ui/core/selection/SelectionManagerLongPressDragTest.kt
M ui/ui-core/src/test/java/androidx/ui/core/selection/SelectionManagerTest.kt
M ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/DeterminateProgressTest.kt
M ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/ContainerTest.kt
M ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/OnPositionedTest.kt
M ui/ui-material/api/0.1.0-dev12.txt
M ui/ui-material/api/current.txt
M ui/ui-material/api/public_plus_experimental_0.1.0-dev12.txt
M ui/ui-material/api/public_plus_experimental_current.txt
M ui/ui-material/api/restricted_0.1.0-dev12.txt
M ui/ui-material/api/restricted_current.txt
M ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/DynamicThemeActivity.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/DrawerTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/ProgressIndicatorTest.kt
M ui/ui-material/src/androidTest/java/androidx/ui/material/RadioGroupUiTest.kt
M ui/ui-material/src/main/java/androidx/ui/material/Color.kt
M ui/ui-material/src/main/java/androidx/ui/material/Scaffold.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/AndroidComposeTestCaseRunnerTest.kt
M ui/ui-test/src/androidTest/java/androidx/ui/test/MultipleComposeRootsTest.kt
M ui/ui-text/src/main/java/androidx/ui/text/CoreText.kt
M ui/ui-text/src/main/java/androidx/ui/text/CoreTextField.kt
ma...@google.com <ma...@google.com> #3
Thanks Jossi, we'll take a look into it :)
ni...@google.com <ni...@google.com> #4
cl...@google.com <cl...@google.com>
as...@gmail.com <as...@gmail.com> #5
Any updates on this? It still crashes in 1.2.0-beta02
ta...@gmail.com <ta...@gmail.com> #6
No updates for this?
[Deleted User] <[Deleted User]> #7
It's still a problem in 1.2.1...
jo...@google.com <jo...@google.com> #8
There are no updates to share on this yet. We'll update when we have news :)
ga...@gmail.com <ga...@gmail.com> #9
Any update on this issue
Fatal Exception: java.lang.IllegalArgumentException: The initial value must have an associated anchor. at androidx.compose.material.SwipeableState.ensureInit$material_release(Swipeable.kt:138) at androidx.compose.material.SwipeableKt$swipeable$3.invoke(Swipeable.kt:594) at androidx.compose.material.SwipeableKt$swipeable$3.invoke(Swipeable.kt:573) at androidx.compose.ui.ComposedModifierKt$materialize$result$1.invoke(ComposedModifier.kt:278) at androidx.compose.ui.ComposedModifierKt$materialize$result$1.invoke(ComposedModifier.kt:273) at androidx.compose.ui.Modifier$Element.foldIn(Modifier.java:110) at androidx.compose.ui.ComposedModifier.foldIn(ComposedModifier.kt) at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:152) at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:152) at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:152) at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:152) at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:152) at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:152) at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:152) at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:152) at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:152) at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:152) at androidx.compose.ui.ComposedModifierKt.materialize(ComposedModifier.kt:273) at androidx.compose.ui.layout.LayoutKt$materializerOf$1.invoke-Deg8D_g(Layout.kt:226) at androidx.compose.ui.layout.LayoutKt$materializerOf$1.invoke(Layout.kt:225) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.animation.AnimatedContentKt$$InternalSyntheticOutline$53$ecb30c9002b8026b405a53f2ba709cfaa8a2c7e1404b01422d70647ebaa2f34c$1.m(AnimatedContentKt.java:2) at androidx.compose.material.SurfaceKt$Surface$1.invoke(Surface.kt:38) at androidx.compose.material.SurfaceKt$Surface$1.invoke(Surface.kt:117) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34) at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228) at androidx.compose.material.SurfaceKt.Surface-F-jzlyU(Surface.kt:114) at androidx.compose.material.ModalBottomSheetKt$ModalBottomSheetLayout$1.invoke(ModalBottomSheet.kt:341) at androidx.compose.material.ModalBottomSheetKt$ModalBottomSheetLayout$1.invoke(ModalBottomSheet.kt:326) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116) at androidx.compose.runtime.internal.ComposableLambdaImpl$invoke$1.invoke(ComposableLambda.jvm.kt:127) at androidx.compose.runtime.internal.ComposableLambdaImpl$invoke$1.invoke(ComposableLambda.jvm.kt:127) at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:145) at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2351) at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2618) at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3205) at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:3183) at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:252) at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(SnapshotStateKt.java:1) at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3183) at androidx.compose.runtime.ComposerImpl.recompose$runtime_release(Composer.kt:3148) at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:746) at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:876) at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:107) at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:485) at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:454) at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:34) at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:109) at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41) at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1106) at android.view.Choreographer.doCallbacks(Choreographer.java:866) at android.view.Choreographer.doFrame(Choreographer.java:792) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1092) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:226) at android.os.Looper.loop(Looper.java:313) at android.app.ActivityThread.main(ActivityThread.java:8669) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
th...@gmail.com <th...@gmail.com> #10
jo...@google.com <jo...@google.com> #11
No updates to share yet. We're working on the underlying APIs at the moment to address this properly.
ap...@google.com <ap...@google.com> #12
Branch: androidx-main
commit 3f94eba802caebc95f8f9055ffb572f6ee72ca2e
Author: Levi Albuquerque <levima@google.com>
Date: Thu Mar 16 15:15:20 2023
Migrating BottomDrawer to use SwipeableV2
Move BottomDrawer to use the new SwipeableV2 APIS.
Relnote: Update BottomDrawer internals to use the new SwipeableV2 APIs. Because of this BottomDrawerState will now only have APIS defined at the class level, it won't inherit methods/properties from SwipeableState. We're using composition with an internal SwipeableV2State. Offset is now a nullable floating point property, the current value and a swipe target value can still be accessed through currentValue and targetValue properties. The previous class level methods such as open/expand/close and properties such as isOpen/isClosed continue to be supported.
Test: Updated tests and added new ones.
Fixes: 178529942
Fixes: 220676296
Change-Id: Iad40c08ca8f48afbc451191c788e80584e874b98
M compose/material/material/api/public_plus_experimental_current.txt
M compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/DrawerTest.kt
M compose/material/material/src/commonMain/kotlin/androidx/compose/material/Drawer.kt
pr...@google.com <pr...@google.com> #13
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.compose.material:material:1.5.0-alpha03
Description
When in landscape and the initial state value is set to
BottomDrawerValue.Expanded
,BottomDrawerLayout
will crash because there's no associated anchor. The same thing goes forModalBottomSheetValue.HalfExpanded
when the sheet height is less thanfullHeight / 2
.BottomDrawerLayout
andModalBottomSheetLayout
should coerce into the nearest state if the requested initial one is not present.I'll post stacktraces + repro later!