<@UFX608MK7> What about a ViewModel property that ...
# compose
s
@Cody Engel What about a ViewModel property that is of a type of a
@Model
class?
c
Yeah that’s what I currently have, my team would probably kick me off the team if this ever made it onto
master
though 😅
Copy code
abstract class ComposeViewModel<T> : ViewModel() {
    // This should return a class annotated with @Model
    abstract val model: T
}

@Model
data class Name(var name: String = "Android")

class NameViewModel : ComposeViewModel<Name>() {
    override val model: Name = Name()
}
s
You can always send your resume to me! 😄
But, seriously, wouldn't this be a good 'work-around' since inheritance with
@Model
won't work?
c
It solves my immediate problem for sure. Moving to
Compose
though I’d like to be done with
LiveData
though
Today we do the stuff Jetpack Compose does behind the scenes by hand with LiveData and it ultimately just gets kind of messy with more complex models
s
Does that ViewModel property of the
@Model
type need to be held by a
LiveData
type? I haven't tried it, but couldn't the ViewModel just instantiate a proper
val
instance of that
@Model
type and have the ViewModel's methods modify that property's properties (that are observed by the
@Model
annotation)?
c
Nope, no LiveData is required with this solution. The value survives state changes and it updates whenever it’s updated as well.
This is a very simple example but I really like how it ends up reading overall, being able to annotate a
ViewModel
with
@Model
would just round things out I think…
Copy code
abstract class ComposeViewModel<T> : ViewModel() {
    // This should return a class annotated with @Model
    abstract val model: T
}

@Model
data class Name(var name: String = "Android")

class NameViewModel : ComposeViewModel<Name>() {
    override val model: Name = Name()
}

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val viewModel = ViewModelProviders.of(this).get(NameViewModel::class.java)
        setContent {
            HelloForm(viewModel.model)
        }
    }
}

@Composable
fun HelloForm(name: Name) = MaterialTheme {
    Column(modifier = Spacing(16.dp)) {
        Greeting(name = name.name)
        TextField(
            value = name.name,
            onValueChange = {
                name.name = it
            }
        )
        Button(text = "New Name")
    }
}

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!", modifier = Spacing(top = 16.dp, bottom = 16.dp))
}
👍 1
…Also the
Button
no longer does anything 😅
s
I agree it would be nicer to be able to annotate the actual ViewModel with
@Model
. Say, in your
onValueChange
you'd wan to invoke a method on your ViewModel (not just change the Name's
name
); then you'd have to pass both the ViewModel and its
@Model
property into the
HelloForm()
function or just pass the ViewModel and always write
viewModel.name
to access the
@Model
instance...
l
Why do you need a
ViewModel
in the first place?
s
To be able to use a ViewModelProvider 😀 To make sure the state survives a config change.
l
Compose should handle it
s
'Should' or 'will'? 😀 I haven't gotten a confirmation on that nor found documentation on that....
c
Compose does not handle that.
And yes Anton, that’s a good point that I didn’t point out. Only passing the LiveData would not be enough, you’d want to call functions directly on the view model