Daniele B
08/13/2020, 3:13 PMclass MainActivity : AppCompatActivity() {
val viewModel = MyViewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyTextComponent(viewModel.state)
}
}
}
@Composable
@ExperimentalCoroutinesApi
fun MyTextComponent(stateFlow: StateFlow<DataModel>) {
val state by stateFlow.collectAsState()
Text(text = state.mytext)
}
But on configuration changes (e.g. device rotation), the Activity gets destroyed, and so the viewModel. Is it better to tie the viewModel to the App class, or which other strategy do you suggest?Halil Ozercan
08/13/2020, 3:17 PMViewModelProvider
to instantiate your ViewModel.
Easiest way to do that would be depending on KTX and using viewModels
delegate. You can look at the example in here https://developer.android.com/kotlin/ktx#fragmentDaniele B
08/13/2020, 3:18 PMDaniele B
08/13/2020, 3:18 PMDaniele B
08/13/2020, 3:19 PMHalil Ozercan
08/13/2020, 3:19 PMDaniele B
08/13/2020, 3:20 PMHalil Ozercan
08/13/2020, 3:21 PMremember
and rememberSavedInstanceState
to initialize them inside composable components.Daniele B
08/13/2020, 3:22 PMHalil Ozercan
08/13/2020, 3:24 PMDaniele B
08/13/2020, 3:30 PMclass JetnewsApplication : Application() {
lateinit var container: AppContainer
override fun onCreate() {
super.onCreate()
container = AppContainerImpl(this)
}
}
class MainActivity : AppCompatActivity() {
val navigationViewModel by viewModels<NavigationViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val appContainer = (application as JetnewsApplication).container
setContent {
JetnewsApp(appContainer, navigationViewModel)
}
}
}
I just realized in Google’s JetNews application, they use this approach to retain objectsDaniele B
08/13/2020, 3:55 PMDaniele B
08/13/2020, 3:55 PMclass TheApp : Application() {
lateinit var viewModel: ViewModel
override fun onCreate() {
super.onCreate()
viewModel = ViewModel()
}
}
class MainActivity : AppCompatActivity() {
lateinit var viewModel : ViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = (application as TheApp).viewModel
setContent {
CovidAppTheme {
MainLayout(viewModel)
}
}
}
}
Ian Lake
08/13/2020, 5:08 PMby viewModels()
call). Creating a Singleton is a terrible alternative since that means it never gets cleared out, unlike Android ViewModels (which do get cleared when the activity is finished)Ian Lake
08/13/2020, 5:08 PMremember
uses a ViewModel under the hood as that is the only way to properly save data across configuration changesDaniele B
08/13/2020, 5:46 PMremember
, but I don’t understand how to apply in the case of StateFlow
. This is my code:Daniele B
08/13/2020, 5:46 PMclass MainActivity : AppCompatActivity() {
val viewModel = MyViewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyTextComponent(viewModel.state)
}
}
}
@Composable
@ExperimentalCoroutinesApi
fun MyTextComponent(stateFlow: StateFlow<DataModel>) {
val state by stateFlow.collectAsState()
Text(text = state.mytext)
}
Ian Lake
08/13/2020, 5:48 PMDaniele B
08/13/2020, 5:50 PMremember
is using the Android ViewModel under the hood, right?Daniele B
08/13/2020, 5:51 PMDaniele B
08/13/2020, 5:51 PMDaniele B
08/13/2020, 5:54 PMDaniele B
08/13/2020, 6:07 PMDaniele B
08/13/2020, 6:09 PMIan Lake
08/13/2020, 6:18 PMDaniele B
08/13/2020, 6:57 PMremember
is the way, but as far as I understand “remember” should be applied inside components, while my StateFlow object is defined inside the Activity.Ian Lake
08/13/2020, 7:00 PM@Composable
that needs to be retained across config changesDaniele B
08/13/2020, 7:08 PMDaniele B
08/13/2020, 7:11 PMIan Lake
08/13/2020, 7:23 PMDaniele B
08/13/2020, 8:42 PMclass AppViewModel : ViewModel() {
val coreModel = CoreViewModel()
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val appViewModel: AppViewModel by viewModels()
setContent {
MyTextComponent(appViewModel.coreModel)
}
}
}
@Composable
@ExperimentalCoroutinesApi
fun MyTextComponent(coreModel: CoreViewModel) {
val state by coreModel.stateFlow.collectAsState()
Text(text = state.mytext)
}
Daniele B
08/13/2020, 8:43 PMDaniele B
08/13/2020, 8:44 PMIan Lake
08/13/2020, 8:53 PMMichal Harakal
08/14/2020, 12:49 PMDaniele B
08/14/2020, 12:51 PMgalex
08/14/2020, 4:56 PMexpect open class ViewModel() {
protected val viewModelScope: CoroutineScope
open fun onCleared()
}
And here’s the Android one:
actual open class ViewModel actual constructor() : ViewModel() {
protected actual val viewModelScope: CoroutineScope = CoroutineScope(Dispatchers.Main)
public actual override fun onCleared() {
super.onCleared()
viewModelScope.cancel()
}
}
Hope that helps!Daniele B
08/14/2020, 5:06 PMgalex
08/15/2020, 10:04 AMgalex
08/15/2020, 10:05 AMexpect open class ViewModel<T>() {
protected val state: StateFlow<T>
open fun onCleared()
}