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.