ViewModelProviders jest przestarzałe w wersji 1.1.0

171

Patrząc na dokumenty Google dla ViewModel, pokazują one poniższy przykładowy kod, jak uzyskać ViewModel:

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

W przypadku korzystania z najnowszej zależności android.arch.lifecycle:extensions:1.1.1nie ma takiej klasy ViewModelProviders.

Przechodząc do dokumentacji dla ViewModelProviders, zobaczyłem komentarz mówiący:

Ta klasa została wycofana na poziomie interfejsu API 1.1.0. Użyj ViewModelProvider.AndroidViewModelFactory

Problem polega na tym, że podczas próby użycia ViewModelProvider.AndroidViewModelFactorynie można znaleźć równoważnej ofmetody, aby uzyskać wystąpienie ViewModel.

Co próbowałem zrobić:

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

Stąd nazwa metody create, za każdym razem, gdy ją wywołuję, otrzymuję nowe wystąpienie ViewModel, co nie jest tym, czego szukam.

Jakieś pomysły, co zastąpi przestarzały kod powyżej?

TareK Khoury
źródło
użyj wzorca singleton lub zmień na AndroidX
Oussema Aroua

Odpowiedzi:

38

UPDATE 2020-06-16 : Obecnie ViewModelProviders jest przestarzały i nie powinien być już używany. To pytanie i odpowiedź pochodziły z końca 2018 roku, kiedy tak nie było. To pytanie i odpowiedź dotyczą również starszej wersji Architecture Components ViewModelProviders, a nie wersji AndroidX.


W przypadku korzystania z najnowszej zależności android.arch.lifecycle:extensions:1.1.1nie ma takiej klasy ViewModelProviders.

Tak jest. Aby to zademonstrować:

  • Utwórz nowy projekt w Android Studio 3.2.1 (z Kotlin, minSdkVersion21, szablon „pusta aktywność”)

  • Dodaj android.arch.lifecycle:extensions:1.1.1do zależności appmodułu

To da ci app/build.gradlepolubienie:

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

Zobaczysz wtedy tę bibliotekę w „Bibliotekach zewnętrznych” z tą klasą:

Biblioteki zewnętrzne

Będziesz mógł odwołać się do tej klasy:

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

Przechodząc do dokumentacji ViewModelProviders, zobaczyłem komentarz mówiący: Ta klasa została wycofana na poziomie API 1.1.0. Użyj ViewModelProvider.AndroidViewModelFactory

Ten komentarz znajduje się pod ViewModelProviders.DefaultFactorywpisem do zajęć i odnosi się do tej klasy, a nie ViewModelProviders:

Zrzut ekranu dokumentacji

Jakieś pomysły, co zastąpi przestarzały kod powyżej?

Użyj ViewModelProviders.

CommonsWare
źródło
1
@TareKKhoury: To by to wyjaśniało! Śledzenie, które moduły wymagają jakich zależności, z pewnością może być wyzwaniem. Miło mi słyszeć, że to działa!
CommonsWare
20
To już nie jest prawdą, już ViewModelProviders.of()nie istnieje.
EpicPandaForce
363

Używam 2.2.0wersji z rozszerzeniami cyklu życia :

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

Powinno działać, używając ViewModelProviderkonstruktora.

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


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

Aktualizacja 2020/5/15

Znajduję inny elegancki sposób na osiągnięcie tego celu, może pomóc Android KTX

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

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

2020/06/25: poprawiono przypadek delegata

Fantasy Fang
źródło
174
Mam dość ciągłego cyklu „amortyzacji” Google.
AFD
3
ViewModelProviders.of () został wycofany. Możesz przekazać Fragment lub FragmentActivity do nowego konstruktora ViewModelProvider (ViewModelStoreOwner), aby osiągnąć tę samą funkcjonalność. (aosp / 1009889)
Raghu Krishnan R
35
Odpowiednik w Javie:YourViewModel viewModel = new ViewModelProvider(this).get(YourViewModel.class);
ban-geoengineering
21
Martwię się, jeśli pewnego dnia Google wycofa TextViewlub EditTexti wprowadzi nowy składnik.
Pranjal Choladhara
4
Androidx Lifecycle-Viewmodel 2.1.0 nie ma konstruktora bez fabryki. używanie po prostu (this) nie działa. ViewModelProvider (ViewModelStoreOwner, Factory) i ViewModelProvider (ViewModelStore, Factory) są jedynymi konstruktorami
DevinM
75

Jak @FantasyFang wspomniał w swojej odpowiedzi, użyj najnowszej wersji, lifecycle:lifecycle-extensionsktóra w tej chwili jest 2.2.0-alpha03. Dlatego w pliku build.gradle należy dodać następujący wiersz:

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

Dla tych, którzy używają Javy, aby rozwiązać ten problem, przekaż te argumenty bezpośrednio do konstruktora ViewModelProvider :

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

Lub jeśli nie korzystasz z fabryki, po prostu użyj:

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

Bez przekazywania obiektu fabrycznego.

Alex Mamo
źródło
1
W build.gradle powinieneś używać następującego: implementacja "androidx.lifecycle: lifecycle-viewmodel: $ lifecycle_version" Jak wspomniano w developer.android.com/jetpack/androidx/releases/lifecycle Interfejsy API w rozszerzeniach cyklu życia zostały wycofane. Zamiast tego dodaj zależności dla określonych artefaktów cyklu życia, których potrzebujesz.
Kenneth Argo
47

Od 2.2.0. rozszerzenia cyklu życia zostały wycofane. Zapoznaj się z dokumentacją Google .

To jest wycięcie ze strony:

Interfejsy API w rozszerzeniach cyklu życia zostały wycofane. Zamiast tego dodaj zależności dla określonych artefaktów cyklu życia, których potrzebujesz.

Nowe biblioteki to:

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

Nowy kod dla JAVA:

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

Lub dla Kotlina:

viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
Kenneth Argo
źródło
Czy zachowujemy isntsance ViewModelProvider, czy też musimy go odtworzyć, w takim przypadku wszystkie podstawowe wystąpienia również zostaną zniszczone. Nie mam powodu, aby go odtwarzać, jeśli chodzi o obejrzenie cyklu życia fragmentu / działania
TheRealChx101
1
Dziękujemy za włączenie Java - niektórzy z nas nadal muszą utrzymywać starszy kod.
zkon
39

Wycofane z: ViewModelProviders.of(this, provider).get(VM::class.java)

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

Braian Coronel
źródło
4
dokładnie to, czego szukałem.
Rahul Bali
27

Na początku 2020 roku firma Google wycofała klasę ViewModelProviders w wersji 2.2.0 biblioteki cyklu życia systemu Androidx.

Nie jest już konieczne używanie ViewModelProviders do tworzenia wystąpienia ViewModel, zamiast tego można przekazać wystąpienie Fragment lub Activity do konstruktora ViewModelProvider.

Jeśli używasz kodu takiego jak:

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

pojawi się ostrzeżenie, że ViewModelProviders jest przestarzałe.

Aby uniknąć używania przestarzałych bibliotek, wprowadź następujące zmiany:

  1. W pliku build.gradle (Module: app) użyj wersji 2.2.0 komponentów cyklu życia:

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

    Jeśli chcesz zamiast tego użyć ViewModel z fragmentu, użyj

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

    fragment-ktx automatycznie dołącza aktywność-ktx, więc nie musisz określać obu w zależnościach.

  2. Musisz określić Java 8 w sekcji 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. W swoim fragmencie lub działaniu zmień import na:

    import androidx.activity.viewModels

  4. Kod do utworzenia ViewModel staje się wtedy:

    val viewModel: CalculatorViewModel by viewModels()
    

    zamiast

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

    Użyj obiektu viewModel jako:

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

    gdzie newNumer jest obiektem LiveData

    W fragmencie, który chcesz udostępnić ViewModel działania, użyjesz

    val viewModel: CalculatorViewModel by activityViewModels()
    

Jest to odpowiednik przekazania wystąpienia Activity w (przestarzałej) ViewModelProviders.of()funkcji.

kgandroid
źródło
20

ViewModelProviders.of () został wycofany. wprowadź opis obrazu tutaj

Użyj konstruktorów ViewModelProvider bezpośrednio, ponieważ teraz obsługują one domyślną rolę ViewModelProvider.Factory.

 mainActivityViewModel = new ViewModelProvider(this).get(MainActivityViewModel.class);
Jan
źródło
15

Prawdopodobnie możesz po prostu użyć:

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

bez konieczności dodawania android.arch.lifecycle:extensions:1.1.1jako zależności.

xiaoyu
źródło
14

Tak @Tarek, jest przestarzały. Użyj teraz z AndroidX:

val yourViewModel = ViewModelProvider.NewInstanceFactory().create(YourVideoModel::class.java)
Paulo Linhares - Packapps
źródło
11
Ta odpowiedź jest błędna. Powinieneś używać, w ViewModelProvider(viewModelStoreOwner, factory).get(YourVideoModel::class.java)przeciwnym razie twój onCleared()nie będzie działał poprawnie, a ViewModel nie zostanie zachowany po zmianie konfiguracji. Nie używaj tej odpowiedzi.
EpicPandaForce
12

Właściwie, co robi ta ViewModelProviders.of()metoda pod maską?

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

Przyjmuje Fragmentjako argument, tworzy ViewModelProviderobiekt i przekazuje fragment bezpośrednio do ViewModelProviderkonstruktora.

Możemy też użyć tego samego sposobu.

Np. Przed:

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

Po:

OurViewModel mOurViewModel = new ViewModelProvider(this).get(OurViewModel.class);
Hayk Mkrtchyan
źródło
1
Jeśli implementujesz Factory, masz inny sposób: ViewModelProviderma konstruktora, który oczekuje zarówno a, jak ViewModelStoreOwneri a Factory.
russellhoff
9

Używam android Xi też miałem ten problem.

Przede wszystkim powinieneś dodać te zależności do Gradle:

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

W moim przypadku $ lifecycle_version to 2.2.0-rc02

Po drugie: import dla ViewModelProviderpowinien być:

import androidx.lifecycle.ViewModelProvider

Następnie możesz zainicjować swój vIewModel, jak na poniższych przykładach:

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

val viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
Igor Fridman
źródło
dziękuję za odpowiedź, ale kiedy go używam, obserwacja modelu Viewmodel i wiązanie danych pól już nie działa
Mosa
Uważam, że androidx.lifecycle:lifecycle-compilerjest przestarzały androidx.lifecycle:lifecycle-common-java8.
Bink
6

Użyj tego:

YourViewModel yourViewModel = new ViewModelProvider.AndroidViewModelFactory(getApplication()).create(YourViewModel.class);
Nirwal
źródło
Jak powiedzieliby mandalorianie:This is the Way!
Starwave
4

Możesz użyć tego zamiast:

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

„this” w nawiasach oznacza właściciela instancji YourViewModel.

Jestem w
źródło
3

Nie jestem ekspertem, ale mam wiersz kodu, który rozwiązał mój problem w Javie. Mam nadzieję, że to komuś pomoże.

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

Jak powiedziałem, chciałbym podać więcej szczegółów, ale to rozwiązało ten problem.

ZeePee
źródło
Ten kod jest nieprawidłowy, onCleared()nie zostanie nazwany w ten sposób, a Twój ViewModel zostanie odtworzony za każdym razem (nie będzie zachowany w przypadku zmian konfiguracji).
EpicPandaForce
Czy możesz wyjaśnić trochę więcej na pewnym przykładzie, co naprawiłoby mój błąd? Proszę, wklej odniesienie do wyjaśnienia lub cokolwiek, co
wyjaśniłoby sprawę
viewModel = new ViewModelProvider(this).get(MyViewModel.class). Jeśli AndroidViewModelnie dostaniesz Application, oznacza to niezgodność wersji między cyklem życia a działaniem / fragmentem.
EpicPandaForce
OK, więc wywołanie getApplicationContext jest nieprawidłowe? Czy powinien to być po prostu getContext?
ZeePee
1
Problem polega na utworzeniu pliku new ViewModelProvider.AndroidViewModelFactory(zamiast pliku new ViewModelProvider(.
EpicPandaForce
1

Kiedy użyjesz sztyletu, przejdziesz przez fabrykę w konstruktorze

  MobileViewModel mobileViewModel = new ViewModelProvider(this,providerFactory).get(MobileViewModel.class);
Apoorv Vardhman
źródło
1

Ta odpowiedź dotyczy Javy, ale możesz zrozumieć główny punkt. Rozwiązanie polega na tym, że musisz użyć ViewModelProvider, ponieważ ViewModelProviders jest przestarzałe :

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

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

Przykładowe użycie to:

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

Nie zapomnij także zaktualizować Zależności Gradle : Sprawdź tutaj, czy są ich ostatnie wersje

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

!!! Uważaj jednak, ponieważ niektóre odpowiedzi zalecają to rozwiązanie, ale u mnie nie zadziałało:

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

Ponieważ kiedy korzystałem w ten sposób, otrzymałem poniżej komunikat o błędzie:

Przyczyna: java.lang.RuntimeException: nie można utworzyć instancji klasy com.canerkaseler.mvvmexample.ViewModel

@canerkaseler

canerkaseler
źródło
Ta odpowiedź jest błędna. Musisz przekazać fabrykę do ViewModelProvider. Jeśli wywołasz bezpośrednio create, onCleared()nie będzie działać poprawnie.
EpicPandaForce
W rzeczywistości dosłownie powiedziałeś, że nie chcesz używać poprawnej odpowiedzi. Wygląda na to, że masz niedopasowanie między swoimi androidx.corei twoimi androidx.lifecyclezależnościami.
EpicPandaForce
Zwykle napisałem fabrykę do ViewModelProvider. Jednak usunąłeś go. ContactViewModel contactViewModel = new ViewModelProvider.AndroidViewModelFactory (getApplication ()). Create (ContactViewModel.class); Dlaczego usunąłeś to z mojej odpowiedzi? Podałeś złe kody.
canerkaseler
0

Jeśli oglądasz wideo z Udacity miejsca, w którym tworzysz, GameViewModela nie chcesz pisać przestarzałego kodu, po prostu zastąp:

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

z następującym kodem:

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

i wróć do czytania jak najszybciej!

F.Mysir
źródło
-1

Spróbuj tego...

 LocationViewModel locationViewModel = new ViewModelProvider(this).get(LocationViewModel.class);
Shrawan
źródło
-2

Jeśli masz tę implementację

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

Spróbuj użyć viewModel = MainViewModel()

Eddy Yoel Fresno Hernández
źródło
Nie jest to sposób na utworzenie wystąpienia modelu widoku. W tym celu musisz użyć klasy ViewModelProvider
Emmanuel Mtali
-5

to powinno działać w ten sposób

 viewModel = ViewModelProviders.of(this@MainActivity).get(MainActivityViewModel::class.java)
Hamdi Hanbali
źródło
1
Podczas gdy Twój kod wystąpiłby, klasa is nie utworzy połączenia ze stanem widoku wymaganym, aby klasa View Model poprawnie reagowała na zdarzenia cyklu życia. Musisz poprawnie wstawiać modele widoku, aby odpowiadały i szanowały cykle życia swoich rodziców, w przeciwnym razie za każdym razem będą odtwarzane na nowo i puste.
Kenneth Argo
Jak wspomniano powyżej w PO i innych; Klasa ViewModelProviders została przestarzała. Zobacz: developer.android.com/reference/androidx/lifecycle/…
Kenneth Argo