https://kotlinlang.org logo
#compose
Title
# compose
s

streetsofboston

10/24/2019, 5:41 AM
@Cody Engel What about a ViewModel property that is of a type of a
@Model
class?
c

Cody Engel

10/24/2019, 5:42 AM
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

streetsofboston

10/24/2019, 5:43 AM
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

Cody Engel

10/24/2019, 5:45 AM
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

streetsofboston

10/24/2019, 5:50 AM
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

Cody Engel

10/24/2019, 5:52 AM
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

streetsofboston

10/24/2019, 6:03 AM
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

Luca Nicoletti

10/24/2019, 7:47 AM
Why do you need a
ViewModel
in the first place?
s

streetsofboston

10/24/2019, 2:51 PM
To be able to use a ViewModelProvider 😀 To make sure the state survives a config change.
l

Luca Nicoletti

10/24/2019, 2:53 PM
Compose should handle it
s

streetsofboston

10/24/2019, 2:56 PM
'Should' or 'will'? 😀 I haven't gotten a confirmation on that nor found documentation on that....
c

Cody Engel

10/24/2019, 3:29 PM
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