web-dev-qa-db-fra.com

comment instancier ViewModel dans AndroidX?

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

12

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.

18
Ricardo Costeira

(Comment) Utilisez ViewModel de Android Architecture Component:

  1. 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()
        }
    }
    
  2. 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.)

  3. 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

3
Jeel Vankhede

Mise à jour de ViewModel vers Lifecycle Version 2.2. et supérieur

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

Initialize VM as Class Instance Val

class Fragment : Fragment() {
    private val viewModel: SomeViewModel by viewModels()

    private fun observeViewState() {
        viewModel.feedViewState.observe(viewLifecycleOwner) { viewState ->
            //viewState used here.
        }
    }
}

Initialize VM in onCreate and Reassign Class Instance Var

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.
        }
    }
}

Passer des arguments/paramètres

// 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") } 
}

Activation de SavedState avec des arguments/paramètres

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
    }
}
1
Adam Hurwitz