ViewModelProviders застаріло в 1.1.0


148

Переглядаючи документи Google для ViewModel, вони показують наведений нижче зразок коду, як отримати ViewModel:

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

При використанні останньої залежності android.arch.lifecycle:extensions:1.1.1такого класу немає ViewModelProviders.

Перехід до документації для ViewModelProviders, я побачив коментар , кажучи:

Цей клас застарілий на рівні API 1.0.0. Використовуйте ViewModelProvider.AndroidViewModelFactory

Проблема полягає в тому, що при спробі використання ViewModelProvider.AndroidViewModelFactoryне можна знайти еквівалентний ofметод для отримання екземпляра ViewModel.

Що я намагався робити:

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

Звідси і назва методу create, я отримую новий екземпляр ViewModel кожного разу, коли я його називаю, а це не те, що я шукаю.

Будь-які ідеї, що є заміною застарілого коду вище?


скористайтеся одинарним малюнком або перейдіть на AndroidX
Oussema Aroua

Відповіді:


31

ОНОВЛЕННЯ 2020-06-16 : На даний момент ViewModelProviders застаріла і більше не повинна використовуватися. Це питання та відповіді були з кінця 2018 року, коли цього не було. Це запитання та відповідь стосуються і старішої версії архітектурних компонентів ViewModelProviders, а не версії AndroidX.


При використанні останньої залежності android.arch.lifecycle:extensions:1.1.1такого класу немає ViewModelProviders.

Так, є. Щоб продемонструвати це:

  • Створіть новий проект в Android Studio 3.2.1 (з Kotlin, minSdkVersion21, шаблон "порожня активність")

  • Додайте android.arch.lifecycle:extensions:1.1.1до залежностей appмодуля

Це допоможе вам app/build.gradle:

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

Потім ви побачите, що бібліотека відображається у "Зовнішніх бібліотеках" з цим класом:

Зовнішні бібліотеки

І ви зможете посилатися на цей клас:

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

Переходячи до документації для ViewModelProviders, я побачив коментар, який говорить: Цей клас застарілий у рівні API 1.1.0. Використовуйте ViewModelProvider.AndroidViewModelFactory

Цей коментар знаходиться під ViewModelProviders.DefaultFactoryзаписом класу і стосується цього класу, а не ViewModelProviders:

Скріншот документації

Будь-які ідеї, що є заміною застарілого коду вище?

Використовуйте ViewModelProviders.


1
@TareKKhoury: Це пояснило б це! Відстеження, які саме модулі потребують, які залежності, безумовно, може бути проблемою. Я радий почути, що у вас це працює!
CommonsWare

13
Це вже не так, ViewModelProviders.of()більше не існує.
EpicPandaForce

323

Я використовую 2.2.0версію розширень життєвого циклу :

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

Це має бути робота, використовуючи ViewModelProviderконструктор.

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


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

Оновлення 2020/5/15

Я знаходжу ще один елегантний спосіб досягти, Android KTX може допомогти

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

Посилання: https://developer.android.com/reference/kotlin/androidx/fragment/app/package-summary#viewmodels

2020/06/25: виправлено справу делегата


161
Мені якось нудно від постійного циклу "амортизації" від Google.
AFD

3
ViewModelProviders.of () застарілий. Ви можете передати фрагмент або FragmentActivity новому конструктору ViewModelProvider (ViewModelStoreOwner) для досягнення тієї ж функціональності. (aosp / 1009889)
Raghu Krishnan R

32
Java-еквівалент:YourViewModel viewModel = new ViewModelProvider(this).get(YourViewModel.class);
заборона-геоінженерія

16
Я хвилююся, якщо якихось днів Google зневажить TextViewабо EditTextвведе новий компонент.
Пранджал Чоладхара

4
androidx lifecycle-viewmodel 2.1.0 не має конструктора без фабрики. використання просто (це) не працює. ViewModelProvider (ViewModelStoreOwner, Factory) і ViewModelProvider (ViewModelStore, Factory) - єдині конструктори
DevinM

70

Як згадував @FantasyFang у своїй відповіді, використовуйте найсвіжішу версію, для lifecycle:lifecycle-extensionsякої в даний момент є 2.2.0-alpha03. Тож слід додати у свій файл build.gradle такий рядок:

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

Для тих, хто використовує Java, для вирішення цього питання передайте ці аргументи безпосередньо конструктору ViewModelProvider :

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

Або якщо ви не використовуєте фабрику, просто використовуйте:

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

Не передаючи заводський об’єкт.


1
У build.gradle вам слід використовувати наступне: реалізація "androidx.lifecycle: lifecycle-viewmodel: $ lifecycle_version" Як зазначено в developer.android.com/jetpack/androidx/releases/lifecycle API-інтерфейси в розширеннях життєвого циклу застаріли. Натомість додайте залежності для конкретних артефактів життєвого циклу, які вам потрібні.
Кеннет Арго

40

Станом на 2.2.0. продовження життєвого циклу застаріле. Див. Документацію Google .

Це вирізання зі сторінки:

API в розширеннях життєвого циклу застарілі. Натомість додайте залежності для конкретних артефактів життєвого циклу, які вам потрібні.

Нові бібліотеки:

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

Новий код для JAVA:

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

Або для Котліна:

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

Чи збережемо вигляд ViewModelProvider чи доведеться його відтворити знову, і в цьому випадку всі базові екземпляри також будуть знищені. Я не є причиною його створення, якщо ідея полягає у перегляді життєвого циклу фрагмента / діяльності
TheRealChx101


22

На початку 2020 року Google припинив клас ViewModelProviders у версії 2.2.0 бібліотеки життєвого циклу androidx.

Більше не потрібно використовувати ViewModelProviders для створення примірника ViewModel, ви можете передати свій екземпляр фрагмента чи активності замість цього конструктору ViewModelProvider.

Якщо ви використовуєте такий код, як:

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

ви отримаєте попередження, що ViewModelProviders застарілий.

Щоб уникнути використання застарілих бібліотек, внесіть такі зміни:

  1. У файлі build.gradle (Модуль: додаток) використовуйте версію 2.2.0 компонентів життєвого циклу:

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

    Якщо ви хочете використовувати ViewModel з фрагмента замість цього, використовуйте

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

    fragment-ktx автоматично включає в себе Activity-ktx, тому вам не потрібно вказувати обидва в залежності.

  2. Вам потрібно вказати Java 8 у розділі андроїд:

    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. У своєму фрагменті чи активності змініть імпорт на:

    імпортувати androidx.activity.viewModels

  4. Код для створення ViewModel потім стає:

    val viewModel: CalculatorViewModel by viewModels()

    замість

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

    Використовуйте об'єкт viewModel як:

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

    де newNumer - об’єкт LiveData

    У фрагменті, яким ви хочете поділитися ViewModel діяльності, ви використовуєте

    val viewModel: CalculatorViewModel by activityViewModels()

Це еквівалент передачі екземпляру Activity у (застарілій) ViewModelProviders.of()функції.


17

ViewModelProviders.of () застарілий. введіть тут опис зображення

Використовуйте конструктори ViewModelProvider безпосередньо, оскільки вони тепер обробляють роль ViewModelProvider.Factory за замовчуванням.

 mainActivityViewModel = new ViewModelProvider(this).get(MainActivityViewModel.class);

13

Так @Tarek, це застаріле. Використовуйте зараз з AndroidX:

val yourViewModel = ViewModelProvider.NewInstanceFactory().create(YourVideoModel::class.java)

5
Ця відповідь неправильна. Ви повинні використовувати ViewModelProvider(viewModelStoreOwner, factory).get(YourVideoModel::class.java)інше, якщо onCleared()ви не будете працювати належним чином, і ViewModel не буде зберігатися через зміну конфігурації. Не використовуйте цю відповідь.
EpicPandaForce

13

Можливо, ви можете просто використовувати:

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

без необхідності додавати android.arch.lifecycle:extensions:1.1.1як залежність.



8

Я використовую, android Xі у мене також була ця проблема.

Перш за все , слід додати ці залежності до своїх Gradle:

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

У моєму випадку $ lifecycle_version був 2.2.0-rc02

По-друге: Імпорт ViewModelProviderповинен бути:

import androidx.lifecycle.ViewModelProvider

Чим ви можете ініціювати свій vIewModel, як наведено нижче:

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

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

дякую за Вашу відповідь, але коли я використовую її, то viewmodel спостерігати і пов’язання даних полів вже не працює
Mosa

Я вважаю, androidx.lifecycle:lifecycle-compilerце застаріло androidx.lifecycle:lifecycle-common-java8.
Бінк

8

Власне, що робить ViewModelProviders.of()метод під кришкою?

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

Він бере Fragmentаргумент, створює ViewModelProviderоб'єкт і передає фрагмент безпосередньо ViewModelProviderконструктору.

Ми можемо використовувати те саме.

Наприклад перед:

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

Після:

OurViewModel mOurViewModel = new ViewModelProvider(this).get(OurViewModel.class);

Якщо ви реалізуєте Factory, у вас є інший шлях: ViewModelProviderмає конструктор, який очікує і a, ViewModelStoreOwnerі a Factory.
russellhoff


3

Я не експерт, але у мене є рядок коду, який вирішив мою проблему на Java. Сподіваюся, що це комусь допоможе.

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

Як я сказав, я хотів би надати більше деталей, але це вирішило цю проблему для мене.


Цей код невірний, onCleared()його не буде називатися таким чином, і ваш ViewModel буде відтворюватися кожен раз (не зберігається для змін конфігурації).
EpicPandaForce

Чи можете ви пояснити трохи більше на прикладі, що могло б виправити мою помилку? Будь ласка, вставте посилання на пояснення чи будь-що, що зробило б зрозуміліші речі
ZeePee

viewModel = new ViewModelProvider(this).get(MyViewModel.class). Якщо ви AndroidViewModelне отримали Application, то у вас є невідповідність версії між життєвим циклом та активністю / фрагментом.
EpicPandaForce

Гаразд, тому виклик getApplicationContext невірний? Чи повинен це просто бути getContext?
ZeePee

1
Проблема полягає у створенні new ViewModelProvider.AndroidViewModelFactory(замість new ViewModelProvider(.
EpicPandaForce

3

Використовуй це:

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

2

Ви можете використовувати це замість:

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

"це" в дужках є власником екземпляра YourViewModel.


1

Ця відповідь стосується Java, але ви можете зрозуміти головне. Рішення полягає в тому, що вам потрібно використовувати ViewModelProvider, оскільки застарілий ViewModelProviders застарілий :

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

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

Приклад використання:

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

Крім того, не забудьте оновити залежності Gradle : Ознайомтесь з останніми версіями їх

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

!!! Однак будьте обережні, оскільки деякі відповіді рекомендують це рішення, але це не спрацювало для мене:

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

Тому що, використовуючи цей спосіб, я потрапив нижче Повідомлення про помилку:

Викликано: java.lang.RuntimeException: Неможливо створити екземпляр класу com.canerkaseler.mvvmexample.ViewModel

@canerkaseler


Ця відповідь неправильна. Вам потрібно передати фабрику ViewModelProvider. Якщо ви прямо посилаєтесь create, то onCleared()це не буде правильним.
EpicPandaForce

Насправді ви буквально просто сказали не використовувати правильну відповідь. Схоже, у вас невідповідність між вашими androidx.coreта вашими androidx.lifecycleзалежностями.
EpicPandaForce

Зазвичай я написав завод на ViewModelProvider. Однак ви її видалили. ContactViewModel contactViewModel = новий ViewModelProvider.AndroidViewModelFactory (getApplication ()). Створити (ContactViewModel.class); Чому ви видалили його на мою відповідь? Ви передали неправильні коди.
canerkaseler

0

Якщо ви використовуєте кинджал, тоді ви передасте завод у конструктор

  MobileViewModel mobileViewModel = new ViewModelProvider(this,providerFactory).get(MobileViewModel.class);


-2

Спробуйте це...

 LocationViewModel locationViewModel = new ViewModelProvider(this).get(LocationViewModel.class);

-5

це має працювати так

 viewModel = ViewModelProviders.of(this@MainActivity).get(MainActivityViewModel::class.java)

1
Хоча ваш код буде, наприклад, клас не створить з'єднання зі станом перегляду, необхідним для класу View Model, щоб правильно реагувати на події життєвого циклу. Потрібно, наприклад, переглядати Моделі правильно, щоб вони відповідали та шанували життєві цикли своїх батьків, тому що кожного разу вони будуть відтворені свіжими та порожніми.
Кеннет Арго

Як зазначалося вище ОП та інші; клас ViewModelProviders застарілий. Дивіться: developer.android.com/reference/androidx/lifecycle/…
Кеннет Арго
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.