ViewModelProviders устарела в 1.1.0


149

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

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

При использовании последней зависимости android.arch.lifecycle:extensions:1.1.1такого класса нет ViewModelProviders.

Переходя к документации для ViewModelProviders, я увидел комментарий:

Этот класс объявлен устаревшим на уровне API 1.1.0. Используйте ViewModelProvider.AndroidViewModelFactory

Проблема в том, что при попытке использования ViewModelProvider.AndroidViewModelFactoryне удается найти эквивалентный ofметод для получения экземпляра ViewModel.

Что я пытался сделать:

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

Отсюда и название метода create, я получаю новый экземпляр ViewModel каждый раз, когда я его вызываю, но это не то, что мне нужно.

Есть идеи, что такое замена устаревшего кода выше?


используйте шаблон синглтона или измените на AndroidX
Oussema Aroua

Ответы:


32

ОБНОВЛЕНИЕ 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

14
Это больше не верно, ViewModelProviders.of()больше не существует.
EpicPandaForce

326

Я использую 2.2.0версию Lifecycle-Extension :

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 () устарел. Вы можете передать Fragment или FragmentActivity новому конструктору ViewModelProvider (ViewModelStoreOwner) для достижения той же функциональности. (aosp / 1009889)
Рагху Кришнан Р

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-интерфейсы в расширениях жизненного цикла устарели. Вместо этого добавьте зависимости для конкретных артефактов жизненного цикла, которые вам нужны.
Кеннет Арго

41

По состоянию на 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)

Сохраняем ли мы isntsance ViewModelProvider или должны воссоздавать его снова, и в этом случае все базовые экземпляры также будут уничтожены. Я не
являюсь


22

В начале 2020 года Google исключил класс ViewModelProviders в версии 2.2.0 библиотеки жизненного цикла androidx.

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

Если вы используете такой код:

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

вы получите предупреждение о том, что ViewModelProviders устарел.

Чтобы избежать использования устаревших библиотек, внесите следующие изменения:

  1. В файле build.gradle (Module: app) используйте версию 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. В разделе android нужно указать 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 Activity, вы должны использовать

    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
Этот ответ неверен. Вы должны использовать a, 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)

спасибо за ваш ответ, но когда я использую его, тогда просмотр модели просмотра и привязка данных к полям больше не работают
Моса,

Я считаю 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)

«this» в скобках - владелец экземпляра 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 ()). Create (ContactViewModel.class); Почему вы удалили его в моем ответе? Вы ввели неправильные коды.
canerkaseler

0

Когда вы используете кинжал, вы передадите factory в конструкторе

  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 Models, чтобы они реагировали и соблюдали жизненные циклы своих родителей, иначе они каждый раз воссоздались свежими и пустыми.
Кеннет Арго,

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