Je veux initialiser ViewModel dans Activity en utilisant la bibliothèque androidx
J'ai essayé ce que dit la documentation mais cela ne fonctionne pas. le ".of" n'est pas résolu.
import androidx.appcompat.app.AppCompatActivity
import Android.os.Bundle import androidx.databinding.DataBindingUtil import androidx.lifecycle.ViewModelProvider import com.example.myapplication.databinding.ActivityMainBinding
class MainActivity: AppCompatActivity () {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(
this, R.layout.activity_main)
binding.setLifecycleOwner(this)
var model = ViewModelProvider.of(this).get(SheduleViewModel::class.Java)
}
}
n'est pas résolu, il peut y avoir d'autres moyens de le faire dans androidx
Réponse mise à jour:
Les choses ont changé un peu, comme la dépendance précédemment nécessaire - ViewModelProviders
- obsolète (voir l'ancienne réponse pour plus de détails). Vous pouvez maintenant utiliser directement le constructeur ViewModelProvider
.
Donc, dans ce cas, la réponse serait:
private val viewModel = ViewModelProvider(this).get(SheduleViewModel::class.Java)
Notez cependant que si vous instanciez un ViewModel
dans un Fragment
, vous pouvez ajouter la dépendance androidx.fragment:fragment-ktx:$Version
, Puis utiliser la délégation de propriété:
private val viewModel: SheduleViewModel by viewModels()
Qui en interne utilisera ViewModelProvider
et étendra votre ViewModel
à votre Fragment
. C'est juste une façon plus concise d'écrire la même chose.
Le constructeur ViewModelProvider
et by viewModels()
acceptent également une fabrique comme paramètre (utile pour injecter votre ViewModel
):
private val viewModel =
ViewModelProvider(this, viewModelFactory).get(SheduleViewModel::class.Java)
et
private val viewModel: SheduleViewModel by viewModels { viewModelFactory }
Utilisez celui qui vous convient le mieux.
Ancienne réponse:
Ajoutez la dépendance androidx.lifecycle:lifecycle-extensions:$lifecycleExtensionsVersion
Afin d'importer ViewModelProviders
.
(Comment) Utilisez ViewModel
de Android Architecture Component:
Ajoutez le référentiel Google Maven (Facultatif, vérifiez juste que)
Les projets Android Studio ne sont pas configurés pour accéder à ce référentiel par défaut.
Pour l'ajouter à votre projet, ouvrez le fichier build.gradle
De votre projet (pas celui de votre application ou module) et ajoutez le google()
référentiel comme indiqué ci-dessous:
allprojects {
repositories {
google()
jcenter()
}
}
Déclaration des dépendances
Ouvrez votre fichier build.gradle
Au niveau de l'application,
Allez à dependencies{}
bloc
Mettez implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
Pour AndroidX version, $ lifecycle_version voici la dernière version définie.
Pour Pre-AndroidX utilisez implementation "Android.Arch.lifecycle:viewmodel:1.1.1"
(1.1.1 est la dernière version de cet artefact je suppose.)
Dans votre activité, utilisez comme cette syntaxe
Importez cette classe:
import androidx.lifecycle.ViewModelProviders;
Pour AndroidX
import Android.Arch.lifecycle.ViewModelProviders;
Lors de l'utilisation de Pre-AndroidX
Et obtenez votre ViewModel
comme suit
ViewModelProviders.of(this).get(ProfileObservableViewModel::class.Java)
// Syntaxe Kotlin
---- ou ----
ViewModelProviders.of(this).get(ProfileObservableViewModel.class);
// Java
Les ViewModels (VMs) peuvent théoriquement être initialisés en tant que variables d'instance au niveau classe en utilisant la bibliothèque d'extensions Kotlin import androidx.fragment.app.viewModels
Méthode by viewmodels()
. En initialisant le VM en tant qu'instance de niveau var, on peut y accéder au sein de la classe.
Question: Y a-t-il un inconvénient à initialiser les VM en tant que variables d'instance au niveau de la classe au lieu de l'intérieur onCreate
?
Lors de la création de machines virtuelles avec la fonction d'extension à l'intérieur de onCreate
, les machines virtuelles sont uniquement étendues dans onCreate
et du code supplémentaire est requis pour réaffecter les variables d'instance au niveau de la classe.
Voir la documentation
class Fragment : Fragment() {
private val viewModel: SomeViewModel by viewModels()
private fun observeViewState() {
viewModel.feedViewState.observe(viewLifecycleOwner) { viewState ->
//viewState used here.
}
}
}
class Fragment : Fragment() {
private lateinit var viewModel: SomeViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val viewModel: ContentViewModel by viewModels()
this.viewModel = viewModel
}
private fun observeViewState() {
viewModel.feedViewState.observe(viewLifecycleOwner) { viewState ->
//viewState used here.
}
}
}
// Override ViewModelProvider.NewInstanceFactory to create the ViewModel (VM).
class SomeViewModelFactory(private val someString: String): ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>): T = SomeViewModel(someString) as T
}
class SomeViewModel(private val someString: String) : ViewModel() {
init {
//TODO: Use 'someString' to init process when VM is created. i.e. Get data request.
}
}
class Fragment: Fragment() {
// Create VM in activity/fragment with VM factory.
val someViewModel: SomeViewModel by viewModels { SomeViewModelFactory("someString") }
}
class SomeViewModelFactory(
private val owner: SavedStateRegistryOwner,
private val someString: String) : AbstractSavedStateViewModelFactory(owner, null) {
override fun <T : ViewModel?> create(key: String, modelClass: Class<T>, state: SavedStateHandle) =
SomeViewModel(state, someString) as T
}
class SomeViewModel(private val state: SavedStateHandle, private val someString: String) : ViewModel() {
val feedPosition = state.get<Int>(FEED_POSITION_KEY).let { position ->
if (position == null) 0 else position
}
init {
//TODO: Use 'someString' to init process when VM is created. i.e. Get data request.
}
fun saveFeedPosition(position: Int) {
state.set(FEED_POSITION_KEY, position)
}
}
class Fragment: Fragment() {
// Create VM in activity/fragment with VM factory.
val someViewModel: SomeViewModel by viewModels { SomeViewModelFactory(this, "someString") }
private var feedPosition: Int = 0
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
someViewModel.saveFeedPosition((contentRecyclerView.layoutManager as LinearLayoutManager)
.findFirstVisibleItemPosition())
}
override fun onViewStateRestored(savedInstanceState: Bundle?) {
super.onViewStateRestored(savedInstanceState)
feedPosition = someViewModel.feedPosition
}
}