Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

By delegate data class on observeAsState

I want to use the state by delegate syntax on observeAsState, but it report a error show there is no getValue method in data class.

@Composable
fun ComposeScreen(
    ...
) {
    val item: Item by viewModel.item.observeAsState(Item)  // there is an error in `(Item)`, it seems not delegate directly using the model of data class.
}

// viewModel
val item = itemRepository.item  // item is a LiveData 

// model
data class Item(
    ...
)

UPDATE

I find the solution reference other one's demo project, but I still not understand why do this.

import androidx.compose.runtime.getValue

val item: Item? by viewModel.item.observeAsState()
like image 384
ccd Avatar asked Oct 25 '20 09:10

ccd


People also ask

How do you use Remember in compose?

There are three ways to declare a MutableState object in a composable: val mutableState = remember { mutableStateOf(default) } var value by remember { mutableStateOf(default) } val (value, setValue) = remember { mutableStateOf(default) }

Is Jetpack Compose production ready?

Jetpack compose is stable and ready for production but Google still continues to bring new features to the library on every new release, some features are graduated to stable from experimental whilst new features or APIs are introduced as experimental.

How do you recompose a jetpack?

Recomposition. In an imperative UI model, to change a widget, you call a setter on the widget to change its internal state. In Compose, you call the composable function again with new data. Doing so causes the function to be recomposed--the widgets emitted by the function are redrawn, if necessary, with new data.


1 Answers

You need to import it mannualy, like this:

import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue

or

import androidx.compose.runtime.*

I believe it's a bug in Android Studio where it does not suggest to import it automatically.

[EDIT] You edited your question asking why we need that import, so I'll try to wrap it up:

When we want to delegate an assignment to a class using "by", we need to make a function called "getValue" with the "operator" modifier that returns the value in the correct type. It's the same logic for "setValue", we need to ask for a parameter of the right type and use "operator", allowing you to use "by" in a "var", besides "val".

What's happening there is that the function "getValue" and "setValue" are declared as extension functions, so it isn't enough to import "State", you also have to import the top level extension functions that are in a separated file.

Let me know if that explanation was enough, I took me a while to understand that, even thought that the documentation was out of date, by I was missing the import.

P.S. Here are the two functions in Compose's code, as you can see, they extends the "State" class.

inline operator fun <T> State<T>.getValue(thisObj: Any?, property: KProperty<*>): T = value

inline operator fun <T> MutableState<T>.setValue(
        thisObj: Any?, property: KProperty<*>, value: T) {
    this.value = value
}
like image 102
Vitor Ramos Avatar answered Sep 30 '22 00:09

Vitor Ramos