ViewModelProviders est obsolète dans la version 1.1.0

148

En regardant les documents Google pour ViewModel, ils montrent l'exemple de code ci-dessous sur la façon d'obtenir un ViewModel:

val model = ViewModelProviders.of(this).get(MyViewModel::class.java)

Lors de l'utilisation de la dernière dépendance android.arch.lifecycle:extensions:1.1.1, une telle classe n'existe pas ViewModelProviders.

En allant à la documentation pour ViewModelProviders, j'ai vu un commentaire disant:

Cette classe était obsolète au niveau d'API 1.1.0. Utilisez ViewModelProvider.AndroidViewModelFactory

Le problème est que, lorsque vous essayez d'utiliser ViewModelProvider.AndroidViewModelFactory, vous ne trouvez pas de ofméthode équivalente pour obtenir l'instance du ViewModel.

Ce que j'ai essayé de faire:

ViewModelProvider.AndroidViewModelFactory.getInstance(application).create(PlayerViewHolder::class.java)

D'où le nom de la méthode create, j'obtiens une nouvelle instance du ViewModel à chaque fois que je l'appelle, ce qui n'est pas ce que je recherche.

Des idées sur ce qu'est le remplacement du code obsolète ci-dessus?

TareK Khoury
la source
utiliser le modèle singleton ou passer à AndroidX
Oussema Aroua

Réponses:

31

MISE À JOUR 2020-06-16 : est actuellement ViewModelProviders obsolète et ne devrait plus être utilisée. Cette question et cette réponse dataient de fin 2018, alors que ce n'était pas le cas. Cette question et réponse concerne également l'ancienne édition des composants d'architecture ViewModelProviders, et non l'édition AndroidX.


Lors de l'utilisation de la dernière dépendance android.arch.lifecycle:extensions:1.1.1, une telle classe n'existe pas ViewModelProviders.

Oui il y a. Pour démontrer ceci:

  • Créer un nouveau projet dans Android Studio 3.2.1 (avec Kotlin, minSdkVersion21, modèle "activité vide")

  • Ajouter android.arch.lifecycle:extensions:1.1.1aux dépendances du appmodule

Cela vous donnera un app/build.gradlecomme:

apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.commonsware.myandroidarch"
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'android.arch.lifecycle:extensions:1.1.1'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

Vous verrez alors cette bibliothèque apparaître dans "Bibliothèques externes" avec cette classe:

Bibliothèques externes

Et vous pourrez référencer cette classe:

package com.commonsware.myandroidarch

import android.arch.lifecycle.ViewModelProviders
import android.support.v7.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val provider = ViewModelProviders.of(this)
  }
}

En allant à la documentation de ViewModelProviders, j'ai vu un commentaire disant: Cette classe était obsolète au niveau d'API 1.1.0. Utilisez ViewModelProvider.AndroidViewModelFactory

Ce commentaire se trouve sous l' ViewModelProviders.DefaultFactoryentrée de classe et fait référence à cette classe, pas ViewModelProviders:

Capture d'écran de la documentation

Des idées sur ce qu'est le remplacement du code obsolète ci-dessus?

Utilisez ViewModelProviders.

CommonsWare
la source
1
@TareKKhoury: Cela l'expliquerait! Garder une trace de quels modules ont besoin de dépendances peut certainement être un défi. Je suis content d'apprendre que vous l'avez fait fonctionner!
CommonsWare
14
Ce n'est plus vrai, ViewModelProviders.of()n'existe plus.
EpicPandaForce
326

J'utilise la 2.2.0version lifecycle-extensions :

implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" 

Cela devrait être du travail, en utilisant le ViewModelProviderconstructeur.

// With ViewModelFactory   
val viewModel = ViewModelProvider(this, YourViewModelFactory).get(YourViewModel::class.java)


//Without ViewModelFactory
val viewModel = ViewModelProvider(this).get(YourViewModel::class.java)

Mise à jour du 15/05/2020

Je trouve un autre moyen élégant de réaliser, Android KTX peut aider

implementation "androidx.fragment:fragment-ktx:1.2.4"
val viewmodel: MYViewModel by viewModels()
val viewmodel: MYViewModel by viewModels { myFactory } //With factory

Réf: https://developer.android.com/reference/kotlin/androidx/fragment/app/package-summary#viewmodels

2020/06/25: correction du cas du délégué

Fantaisie Fang
la source
161
J'en ai assez du cycle constant de «dépréciation» de Google.
AFD
3
ViewModelProviders.of () est obsolète. Vous pouvez transmettre un Fragment ou FragmentActivity au nouveau constructeur ViewModelProvider (ViewModelStoreOwner) pour obtenir la même fonctionnalité. (aosp / 1009889)
Raghu Krishnan R
32
Équivalent Java:YourViewModel viewModel = new ViewModelProvider(this).get(YourViewModel.class);
ban-geoengineering
16
Je m'inquiète si un jour, Google abandonnera le TextViewou EditTextet introduira un nouveau composant.
Pranjal Choladhara
4
androidx lifecycle-viewmodel 2.1.0 n'a pas de constructeur sans fabrique. utiliser simplement (ceci) ne fonctionne pas. ViewModelProvider (ViewModelStoreOwner, Factory) et ViewModelProvider (ViewModelStore, Factory) sont les seuls constructeurs
DevinM
70

Comme @FantasyFang l'a mentionné dans sa réponse, utilisez la dernière version pour ce lifecycle:lifecycle-extensionsqui est en ce moment 2.2.0-alpha03. Vous devez donc ajouter dans votre fichier build.gradle la ligne suivante:

implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0-alpha03' 

Pour ceux qui utilisent Java, pour résoudre ce problème, transmettez ces arguments directement au constructeur de ViewModelProvider :

MyViewModel viewModel = new ViewModelProvider(this, myViewModelFactory).get(MyViewModel.class);

Ou si vous n'utilisez pas d'usine, utilisez simplement:

MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);

Sans passer votre objet d'usine.

Alex Mamo
la source
1
Vous devez utiliser les éléments suivants dans build.gradle: implementation "androidx.lifecycle: lifecycle-viewmodel: $ lifecycle_version" Comme indiqué dans developer.android.com/jetpack/androidx/releases/lifecycle Les API de lifecycle-extensions sont obsolètes. Ajoutez plutôt des dépendances pour les artefacts de cycle de vie spécifiques dont vous avez besoin.
Kenneth Argo le
41

À partir de 2.2.0. les extensions de cycle de vie sont devenues obsolètes. Reportez-vous à la documentation Google .

Voici la coupe de la page:

Les API des extensions de cycle de vie sont devenues obsolètes. Ajoutez plutôt des dépendances pour les artefacts de cycle de vie spécifiques dont vous avez besoin.

Les nouvelles bibliothèques sont:

// ViewModel and lifecycle support for java
implementation "androidx.lifecycle:lifecycle-viewmodel:${versions.lifecycle}"
implementation "androidx.lifecycle:lifecycle-livedata:${versions.lifecycle}"

// ViewModel and lifecycle support for kotlin
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:${versions.lifecycle}"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:${versions.lifecycle}"

Le nouveau code pour JAVA:

viewModel = new ViewModelProvider(this).get(MyViewModel.class);

Ou pour Kotlin:

viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
Kenneth Argo
la source
Gardons-nous l'isntsance ViewModelProvider ou devons-nous le recréer à nouveau, auquel cas toutes les instances sous-jacentes seront également détruites. Je n'ai pas la raison de le recréer si l'idée est de regarder le cycle de vie du fragment / activité
TheRealChx101
31

Obsolète de: ViewModelProviders.of(this, provider).get(VM::class.java)

À: ViewModelProvider(this, provider).get(VM::class.java)

Braian Coronel
la source
4
exactement ce que je cherchais.
Rahul Bali
22

Début 2020, Google a déconseillé la classe ViewModelProviders , dans la version 2.2.0 de la bibliothèque de cycle de vie androidx.

Il n'est plus nécessaire d'utiliser ViewModelProviders pour créer une instance d'un ViewModel, vous pouvez passer votre instance de Fragment ou Activity au constructeur ViewModelProvider à la place.

Si vous utilisez le code comme:

val viewModel = ViewModelProviders.of(this).get(CalculatorViewModel::class.java)

vous recevrez un avertissement indiquant que ViewModelProviders est obsolète.

Pour éviter d'utiliser des bibliothèques obsolètes, apportez les modifications suivantes:

  1. Dans le fichier build.gradle (Module: app), utilisez la version 2.2.0 des composants du cycle de vie:

    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
    implementation "androidx.activity:activity-ktx:1.1.0"

    Si vous souhaitez utiliser le ViewModel à partir d'un fragment à la place, utilisez

    implementation "androidx.fragment:fragment-ktx:1.2.2"

    fragment-ktx inclut automatiquement activity-ktx, vous n'avez donc pas besoin de spécifier les deux dans les dépendances.

  2. Vous devez spécifier Java 8 dans la section Android:

    android {
        compileSdkVersion 28
        defaultConfig {
            applicationId "com.kgandroid.calculator"
            minSdkVersion 17
            targetSdkVersion 28
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner 
        "androidx.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 
               'proguard-rules.pro'
            }
        }
    
        kotlinOptions { jvmTarget = "1.8" }
    }
  3. Dans votre fragment ou activité, modifiez l'importation en:

    importer androidx.activity.viewModels

  4. Le code pour créer un ViewModel devient alors:

    val viewModel: CalculatorViewModel by viewModels()

    au lieu de

    val viewModel = ViewModelProviders.of(this).get(CalculatorViewModel::class.java)

    Utilisez l'objet viewModel comme:

    val viewModel: CalculatorViewModel by viewModels()
    
    viewModel.newNumber.observe(this, Observer<String> { 
        stringResult -> newNumber.setText(stringResult) 
    })

    newNumer est un objet LiveData

    Dans un fragment que vous souhaitez partager le ViewModel de l'activité, vous utiliseriez

    val viewModel: CalculatorViewModel by activityViewModels()

C'est l'équivalent de passer l'instance Activity dans la fonction (obsolète) ViewModelProviders.of().

kgandroid
la source
17

ViewModelProviders.of () est obsolète. entrez la description de l'image ici

Utilisez directement les constructeurs ViewModelProvider car ils gèrent désormais le rôle ViewModelProvider.Factory par défaut.

 mainActivityViewModel = new ViewModelProvider(this).get(MainActivityViewModel.class);
John
la source
13

Oui @Tarek, il est obsolète. À utiliser maintenant avec AndroidX:

val yourViewModel = ViewModelProvider.NewInstanceFactory().create(YourVideoModel::class.java)
Paulo Linhares - Packapps
la source
5
Cette réponse est fausse. Vous devriez utiliser un ViewModelProvider(viewModelStoreOwner, factory).get(YourVideoModel::class.java)sinon votre onCleared()ne fonctionnera pas correctement, et ViewModel ne sera pas conservé pendant le changement de configuration. N'utilisez pas cette réponse.
EpicPandaForce
13

Vous pouvez probablement simplement utiliser:

val viewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MyViewModel::class.java)

sans avoir besoin d'ajouter android.arch.lifecycle:extensions:1.1.1comme dépendance.

xiaoyu
la source
8

J'utilise android Xet j'ai également ce problème.

Tout d'abord , vous devez ajouter ces dépendances à votre Gradle:

implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" 

Dans mon cas, la $ lifecycle_version était 2.2.0-rc02

Deuxièmement: l'importation pour le ViewModelProviderdevrait être:

import androidx.lifecycle.ViewModelProvider

Ensuite, vous pouvez initialiser votre vIewModel comme les exemples ci-dessous:

val viewModel = ViewModelProvider(this, YourFactoryInstace).get(MainViewModel::class.java)

val viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
Igor Fridman
la source
merci pour votre réponse, mais quand je l'utilise, viewmodel observe et la liaison de données des champs ne fonctionne plus
Mosa
Je crois que androidx.lifecycle:lifecycle-compilerc'est obsolète par androidx.lifecycle:lifecycle-common-java8.
Bink le
8

En fait, que fait la ViewModelProviders.of()méthode sous le capot?

@Deprecated
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment) {
    return new ViewModelProvider(fragment);
}

Il prend Fragmentcomme argument, crée un ViewModelProviderobjet et passe le fragment directement au ViewModelProviderconstructeur.

Nous pouvons également utiliser la même méthode.

Par exemple avant:

OurViewModel mOurViewModel = ViewModelProviders.of(this).get(OurViewModel.class);

Après:

OurViewModel mOurViewModel = new ViewModelProvider(this).get(OurViewModel.class);
Hayk Mkrtchyan
la source
Si vous implémentez une Factory, vous avez un autre moyen: ViewModelProvidera un constructeur qui attend à la fois a ViewModelStoreOwneret a Factory.
russellhoff
3

Je ne suis pas un expert mais j'ai une ligne de code qui a résolu mon problème en Java. J'espère que cela aide quelqu'un.

viewModel = 
new ViewModelProvider
.AndroidViewModelFactory(getApplication())
.create(ViewModel.class);

Comme je l'ai dit, j'aimerais fournir plus de détails, mais cela a résolu ce problème pour moi.

ZeePee
la source
Ce code est erroné, onCleared()ne sera pas appelé de cette façon et votre ViewModel sera recréé à chaque fois (non conservé pour les modifications de configuration).
EpicPandaForce
Pouvez-vous expliquer un peu plus avec un certain exemple, qu'est-ce qui résoudrait mon erreur? S'il vous plaît, collez une référence à l'explication ou à tout ce qui rendrait les choses plus claires
ZeePee
viewModel = new ViewModelProvider(this).get(MyViewModel.class). Si vous AndroidViewModeln'obtenez pas le Application, vous avez une incompatibilité de version entre Lifecycle et Activity / Fragment.
EpicPandaForce
Ok, donc appeler getApplicationContext est faux? Devrait-il être simplement getContext?
ZeePee
1
Le problème est de créer un fichier au new ViewModelProvider.AndroidViewModelFactory(lieu d' un fichier new ViewModelProvider(.
EpicPandaForce
3

Utilisez ceci:

YourViewModel yourViewModel = new ViewModelProvider.AndroidViewModelFactory(getApplication()).create(YourViewModel.class);
Nirwal
la source
2

Vous pouvez utiliser ceci à la place:

viewModel= ViewModelProvider(this).get(YourViewModel::class.java)

"this" entre parenthèses est le propriétaire de l'instance YourViewModel.

Amin
la source
1

Cette réponse est pour Java mais vous pouvez comprendre le point principal. La solution est que vous devez utiliser ViewModelProvider car ViewModelProviders est obsolète :

//Do not forget import it.
import androidx.lifecycle.AndroidViewModel;

ViewModelProvider.AndroidViewModelFactory(getApplication()).create(YourViewModel.class);

Exemple d'utilisation:

YourViewModel yourViewModel = new ViewModelProvider.AndroidViewModelFactory(getApplication()).create(YourViewModel.class);

N'oubliez pas non plus de mettre à jour les dépendances Gradle : vérifiez ici les dernières versions de celles-ci

implementation 'androidx.lifecycle:lifecycle-viewmodel:2.2.0'
annotationProcessor 'androidx.lifecycle:lifecycle-compiler:2.2.0'

!!! Cependant, soyez prudent car certaines réponses recommandent cette solution mais cela n'a pas fonctionné pour moi:

yourViewModel = new ViewModelProvider(this).get(YourViewModel.class);

Parce que lorsque j'ai utilisé de cette façon, j'ai eu le message d'erreur ci-dessous:

Causé par: java.lang.RuntimeException: impossible de créer une instance de la classe com.canerkaseler.mvvmexample.ViewModel

@canerkaseler

canerkaseler
la source
Cette réponse est fausse. Vous devez transmettre la fabrique à un ViewModelProvider. Si vous appelez directement create, onCleared()cela ne fonctionnera pas correctement.
EpicPandaForce
En fait, vous avez littéralement dit de ne pas utiliser la bonne réponse. On dirait que vous aviez un décalage entre androidx.corevos androidx.lifecycledépendances et vos dépendances.
EpicPandaForce
Normalement, j'ai écrit l'usine à ViewModelProvider. Cependant, vous l'avez supprimé. ContactViewModel contactViewModel = nouveau ViewModelProvider.AndroidViewModelFactory (getApplication ()). Create (ContactViewModel.class); Pourquoi l'avez-vous supprimé sur ma réponse? Vous avez passé de mauvais codes.
canerkaseler
0

Lorsque vous utilisez un poignard, vous passerez l'usine dans le constructeur

  MobileViewModel mobileViewModel = new ViewModelProvider(this,providerFactory).get(MobileViewModel.class);
Apoorv Vardhman
la source
-2

Si vous avez cette implémentation

'implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

Essayez d'utiliser viewModel = MainViewModel()

Eddy Yoel Fresno Hernández
la source
Ce n'est pas une manière d'instancier un modèle de vue. Vous devez utiliser la classe ViewModelProvider pour cela
Emmanuel Mtali
-2

Essaye ça...

 LocationViewModel locationViewModel = new ViewModelProvider(this).get(LocationViewModel.class);
Shrawan
la source
-5

ça devrait fonctionner de cette façon

 viewModel = ViewModelProviders.of(this@MainActivity).get(MainActivityViewModel::class.java)
Hamdi Hanbali
la source
1
Bien que votre code instancie la classe, cela ne crée pas la connexion à l'état d'affichage requis pour que la classe View Model réponde correctement aux événements du cycle de vie. Vous devez créer une instance de View Models de la manière correcte afin qu'ils répondent et honorent les cycles de vie de leurs parents, sinon ils seront recréés à chaque fois.
Kenneth Argo le
Comme indiqué ci-dessus par le PO et d'autres; la classe ViewModelProviders est obsolète. Voir: developer.android.com/reference/androidx/lifecycle/…
Kenneth Argo le