Any idea how to deal with viewModel and Composable...
# compose
m
Any idea how to deal with viewModel and Composable? Let's say I want to declare a state inside viewModel and changed it through InputText.
Copy code
class MessageViewModel : ViewModel() {

    var state: MutableState<TextFieldValue> = state { TextFieldValue() }
}
Cause: Functions which invoke @Composable functions must be marked with the @Composable annotation
z
At the ViewModel layer you should probably be using
LiveData
(which is a more general androidx concept), not compose's
State
. That said, if you really want to use the compose tools, use
mutableStateOf
instead of
state
.
👍 1
m
I'll switch to LiveData, thanks! 🙂
s
Actually curious if there's something inherently wrong with using compose
mutableState
in context like this. Apart from separating UI - presentation layer, ofc
z
I think it's easier to test with LiveData. You can technically subscribe to States outside of a composable by directly using the snapshots APIs, but I'm not sure how ergonomic that is at this point.
👍 1
s
A bit of both on this one: If you know it will only be consumed by a composable, then
mutableStateOf
is a great idea. It's a bit more succinct with the same behavior:
Copy code
val myState: Int by mutableStateOf(0)
   private set
If you expect it may be consumed by non-compose UI bits, then
LiveData
is a good idea. We've recently reworked the way state frames work to allow state to be written from a background thread (conflated). This was one of the major motivations previously to use
LiveData
in situations like this.
👍 1
@Zach Klippenstein (he/him) [MOD] what sort of issues have you run into testing state objects?
z
I haven't actually ran into anything, but i was thinking about a test that would want to subscribe to an output and assert on emissions, like RxJava's TestObserver. Although I guess that's only really something you need to do for streams of events. For streams of state it's enough to just read the current state value at different points, so this wouldn't be an issue. tl;dr: I was overthinking it.
s
Yea, my experience so far has been positive (it's actually nice to just treat it as a value and be able to elide the stream behavior in the test). If you do try it and run into any ergonomics definitely would love to make sure that gets filed / fixed. I almost always use state with the
by/private set
transformation, which means I can just treat a read outside of compose as "what's the current value presently" Adding async writes may change that though – and it'd be good to make sure we're providing the API needed for the testing case
👍 1