Es kann keine Instanz der Klasse ViewModel erstellt werden

76

Ich versuche, eine Beispiel-App mit Android-Architekturkomponenten zu schreiben, aber selbst nach tagelangen Versuchen konnte ich sie nicht zum Laufen bringen. Es gibt mir die obige Ausnahme.

Lebenszyklusbesitzer: -

public class MainActivity extends LifecycleActivity {

    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = findViewById(R.id.tv_user);
        PostViewModel viewModel = ViewModelProviders.of(this).get(PostViewModel.class);
        viewModel.loadPosts();
        viewModel.getPost().observe(this, new Observer<Post>() {
            @Override
            public void onChanged(@Nullable Post post) {
                if(post != null) {
                    textView.setText(post.toString());
                }
            }
        });
    }
}

ViewModel: -

public class PostViewModel extends ViewModel {
    private MediatorLiveData<Post> post;
    private PostRepository postRepo;

    PostViewModel() {
        post = new MediatorLiveData<>();
        postRepo = new PostRepository();
    }

    public LiveData<Post> loadPosts() {
        post.addSource(postRepo.getPost(),
                post -> this.post.setValue(post)
        );
        return post;
    }

    @NonNull
    public LiveData<Post> getPost() {
        return post;
    }
}
Parag Kadam
quelle

Antworten:

124

Machen Sie Ihren Konstruktor public.

CommonsWare
quelle
4
So ein kleiner Fehler, aber so große Auswirkungen. Vielen Dank.
Parag Kadam
4
@ParagKadam: Android Studio weiß nicht, dass für die Lebenszykluskomponenten der Konstruktor öffentlich sein muss. Android Studio verwendet nur das, was es durch explizite Code-Referenzen sehen kann.
CommonsWare
20
Immer noch der Fehler in einem Fragment, sind sowohl Klasse als auch Konstruktor bereits öffentlich.
Ahmadalibaloch
4
Mein Konstruktor ist öffentlich, aber ich habe folgende Fehlermeldung erhalten: Auslöser: java.lang.RuntimeException: Es kann keine Instanz der Klasse com.randa.android.model.search.SearchActivityViewModel unter android.arch.lifecycle.ViewModelProvider $ NewInstanceFactory.create (ViewModelProider) erstellt werden .java: 153) unter android.arch.lifecycle.ViewModelProvider $ AndroidViewModelFactory.create (ViewModelProvider.java:210) unter android.arch.lifecycle.ViewModelProvider.get (ViewModelProvider.java:134). get (ViewModelProvider.java:102) bei com.randa.android.
MrVasilev
2
Komisch ist, dass es im Debug-Modus funktioniert, aber abstürzt, wenn die App im Release-Modus kompiliert wird.
mk_
21

Wenn Sie verwenden Hilt, stellen Sie sicher, dass Ihre Aktivität / Ihr Fragment mit @AndroidEntryPointAnmerkungen versehen ist

Sie Qi
quelle
Dies gibt keine Antwort auf die Frage. Um einen Autor zu kritisieren oder um Klärung zu bitten, hinterlassen Sie einen Kommentar unter seinem Beitrag. - Aus dem Rückblick
Andrii Omelchenko
Nun, @AndriiOmelchenko, haben Sie Hilt mit Injektion im viewModel-Konstruktor ausprobiert? weil ich glaube, dass dies ein ehrlicher Fehler ist, den die meisten Entwickler machen werden, der zur Cannot create an instance of class ViewModelLaufzeit zum Absturz führt.
Sie Qi
2
Ich benutze Dagger Hilt und diese Antwort hat mir viel Zeit gespart, danke!
Canberk Ozcelik
Ich mache immer den gleichen Fehler und finde mich hier wieder. Vielen Dank.
UmutTekin vor
19

Stellen Sie sicher, dass Ihr ViewModelKonstruktor nur einen Parameter hat, d Application. H.

Beispiel:

public YourViewModel(Application application) {
    super(application);
    ...
vivek
quelle
1
Danke, ich habe den Konstruktor der ViewModel-Klasse erstellt und zwei Argumente erhalten. Ich habe eines gelöscht und ein gutes Ergebnis erzielt.
Mortezahosseini
1
Ja, es hat nur einen Parameter, aber es stürzt immer noch ab
Jayesh M
2
Warum kann ViewModel nur eine Konfiguration haben? Parameter?
IgorGanapolsky
17

Wenn Sie verwenden, Kotlinstellen Sie sicher , jeder ersetzen annotationProcessorin build.gradlemit kapt.

Mögen:

annotationProcessor "android.arch.persistence.room:compiler:$rootProject.roomVersion"

Wird werden

kapt "android.arch.persistence.room:compiler:$rootProject.roomVersion"

und hinzufügen

apply plugin: 'kotlin-kapt'oben auf der buidl.gradleDatei.

Anmerkungsverarbeitung mit Kotlin

Max
quelle
2
Es hat mein Problem behoben. Es ist möglicherweise nicht die richtige Antwort für Java, aber es ist richtig für "Kann keine Instanz der Klasse ViewModel in Kotlin erstellen"
Eoghan
1
@Eoghan Ich habe die Antwort aus genau dem gleichen Grund gepostet, weil ich eine ganze Weile gebraucht habe, um dieses Problem zu verstehen. Aber ppl sind nicht sanft und stimmen weiter ab lol, obwohl ich klar erwähnt habe, ob Sie Kotlin verwenden.
Max
Es hat mich gerettet, ich hasse diesen Android Logger, ich habe eine Ausnahme über etwas und der Grund ist eigentlich etwas anderes
Milos
@Milos Vielleicht sollten Sie "Protokollfilter" in Android Studio verwenden.
Ab Morphious
12

Ich hatte dieses Problem nach Googles roomdb CodeLab . Die Lösung änderte Folgendes.

Bearbeitet

Fügen Sie der Gradle-Datei die folgenden Build-Abhängigkeiten hinzu (Stand 22.02.2020)

implementation 'androidx.fragment:fragment:1.2.2'
implementation 'androidx.lifecycle:lifecycle-process:2.2.0'
implementation 'androidx.lifecycle:lifecycle-service:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0'
annotationProcessor 'androidx.lifecycle:lifecycle-compiler:2.2.0'

Importe innerhalb des Fragments

import androidx.lifecycle.ViewModelProvider;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;

ViewModel erstellen. Fügen Sie eine der folgenden Methoden hinzu.

Hinweis : Ich habe dies auf viele Arten gesehen. Ich glaube, der richtige Weg ist getDefaultViewModelProviderFactory(). Aber ich habe benutzt requireActivity().

 new ViewModelProvider(requireActivity(),getDefaultViewModelProviderFactory()).get(YourViewModel.class);

|

 new ViewModelProvider(requireActivity()).get(YourViewModel.class);

          

ViewModelProvider-Dokumente

Veraltet

implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0-rc01'
annotationProcessor 'androidx.lifecycle:lifecycle-compiler:2.2.0-rc01'
this.mitch
quelle
2
Die neueste Dokumentation zum Android-Lebenszyklus besagt, dass die Abhängigkeit von Lebenszykluserweiterungen jetzt veraltet ist. Developer.android.com/jetpack/androidx/releases/lifecycle# Wenn ich diese Abhängigkeit jedoch aus der Gradle-Datei entferne, kann keine Instanz der Klasse erstellt werden Ansichtsmodellfehler beim Starten meiner App. Ich habe versucht, alle anderen als aktuell aufgeführten Abhängigkeiten hinzuzufügen, auch die optionalen, aber ohne die Abhängigkeit von Lebenszykluserweiterungen funktioniert dies nicht. Im Moment muss ich die veraltete Abhängigkeit beibehalten. Ich versuche immer noch herauszufinden, warum es ohne diese Abhängigkeit fehlschlägt.
Howard
Gute Infos @Howard, ich habe meine Antwort basierend auf Ihrem Kommentar aktualisiert.
this.mitch
Vielen Dank für diese Antwort, ich hatte das gleiche Problem nach roomdb CodeLab. Das einzige, was ich hinzufügen musste, war die Implementierung 'androidx.fragment: fragment: 1.2.5'
Rck
7

Es gibt nur wenige Gründe, die Ausnahme auszulösen. Ich habe einige von ihnen erwähnt.

  1. Stellen Sie sicher, dass Ihre Ansicht Modellklasse öffentlich ist
  2. Stellen Sie sicher, dass der Konstruktor Ihrer Ansichtsmodellklasse öffentlich ist

  3. Stellen Sie sicher, dass Sie die Abhängigkeit für den Lebenszyklus in Ihrer Gridle-Datei hinzugefügt haben, auch wenn Sie den von Ihnen hinzugefügten Raum und andere Bibliotheken verwenden.

  4. Wenn Sie eine andere abhängige Klasse in Ihrem Klassenkonstruktor für Ansichtsmodelle erstellen. Andere Klassen können Fehler auslösen, um die Instanz von viewModel zu erstellen
Hoque MD Zahidul
quelle
1
Großartig für den 4. Punkt !!! Es löst mich wirklich, nachdem ich Ihre schrittweise Lösung gefunden habe.
Vji
6

Es war mir nicht ganz klar, aber als ich diesen Fehler bekam, habe ich ihn durch Erstellen eines öffentlichen Konstruktors behoben. Mein Konstruktor wurde aus den Android Developer-Beispielen abgeleitet und enthielt das Repository als Parameter. Durch das Erstellen eines zusätzlichen Konstruktors, der ohne Parameter leer war, und dessen Veröffentlichung wurde das Problem behoben.

dh in Ihrem Fall

public PostViewModel() {}

Brandon
quelle
Was ist, wenn wir Parameter an ViewModel übergeben müssen?
IgorGanapolsky
Sie können einen zusätzlichen Konstruktor für diesen erstellen, aber ein NoArgsConstructor ist erforderlich, um dieses Problem zu lösen.
Brandon
Wo ist die offizielle Dokumentation, die dies belegt?
IgorGanapolsky
6

Machen Sie die Klasse und den Konstruktor öffentlich, es hat mein Problem gelöst.

RaghavPai
quelle
4

Wenn Sie in Ihrer Aktivität das Ansichtsmodell verwendet haben, überprüfen Sie, ob Ihre Aktivität "DaggerAppCompatActivity" erweitert oder nicht

Zum Beispiel

public class UserComments extends AppCompatActivity 

Ändern Sie dies in

public class UserComments extends DaggerAppCompatActivity
Afjalur Rahman Rana
quelle
3
  1. Meistens macht Solution Class und Constructor als andere Antworten öffentlich
  2. Es kann sich auch um einen Laufzeitfehler handeln. Überprüfen Sie die Logcat-Fehlerprotokolle, wenn mehrere Ursachen aufgeführt sind.
lomec
quelle
1
Ja, es ist sehr wichtig, dass die Klasse auch ist public.
Kurt Huwig
3

Erweitern Sie AndroidViewModel aus Ihrer ViewModel-Klasse.

public class YourViewModel extends AndroidViewModel {

    public YourViewModel(Application application) {
        super(application);

        //Todo: ...
    }

}
Zeero0
quelle
3

Wenn Sie Hilt verwenden, vergessen Sie nicht, diese vier Abhängigkeiten hinzuzufügen.

    implementation "com.google.dagger:hilt-android:2.28-alpha"
    kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
    implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01'
    kapt "androidx.hilt:hilt-compiler:1.0.0-alpha01"

Hinweis: - Wenn eine dieser Abhängigkeiten fehlt, wird eine Cannot create an instance of class ViewModelFehlermeldung angezeigt

iamkdblue
quelle
Ich habe alle 4 noch bekomme ich diesen Fehler. Ich habe 2 Ansicht Modell 1 auf Splash funktioniert gut 1 zu Hause gibt diesen Fehler -__ 0. Obwohl später kopiert wird
Dr. aNdRO
Diese Antwort hat mir geholfen. Mir fehlte kapt "androidx.hilt: hilt-compiler: 1.0.0-alpha01" . Das allein hat verhindert, dass mein ViewModel (mit Parametern im Konstruktor, keine ViewModelFactory) erstellt wurde.
user1987392
1
Du bist mein Held. Sie sparen meine Zeit, danke
andika_kurniawan
@andika_kurniawan Sie können die Antwort Ihres Helden positiv bewerten.
iamkdblue
lol, sicher werde ich abstimmen
andika_kurniawan
2

Ich habe dies nach der Migration auf AndroidX erhalten.

Es gibt einen Fehler, bei androidx.lifecycle:lifecycle-viewmodel:2.0.0-beta01dem Proguard den Konstruktor entfernt.

https://issuetracker.google.com/issues/112230489

Beheben Sie das Problem durch ein Upgrade auf 2.0.0 und denken Sie daran, Ihre Proguard-Regeln bei Bedarf zu aktualisieren.

Meine Fehlermeldung sah folgendermaßen aus:

java.lang.RuntimeException: Cannot create an instance of class my.custom.viewmodel.CustomViewModel
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:202)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:135)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:103)
......
Caused by: java.lang.NoSuchMethodException: <init> [class android.app.Application]
at java.lang.Class.getConstructor0(Class.java:2204)
at java.lang.Class.getConstructor(Class.java:1683)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:200)
... 34 more


  androidx.test.espresso.PerformException: Error performing 'single click - At Coordinates: 539, 1167 and precision: 16, 16' on view 'with id: my.test:id/button_return_to_main_menu'.
at androidx.test.espresso.PerformException$Builder.build(PerformException.java:82)
at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:79)
.....
Caused by: java.lang.RuntimeException: Unable to start activity ComponentInfo{my.custom.domain.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class my.custom.viewmodel.CustomViewModel
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
Lydia Ralph
quelle
2

Wenn Ihre PostViewModel-Klasse eine innere Klasse ist, stellen Sie sicher, dass sie öffentlich und statisch ist

Lasitha Lakmal
quelle
1

In meinem Fall war es ein Abhängigkeitsproblem.

Wenn Sie Livedata verwenden ,,

build.gradle (Module.app)

nicht

implementation 'android.arch.lifecycle:extensions:1.1.1'
kapt 'android.arch.lifecycle:common-java8:1.1.1'

benutze diese

implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
kapt 'androidx.lifecycle:lifecycle-common-java8:2.2.0'
J. Dragon
quelle
1

DggerHilt kann auch der Grund sein, wenn Sie verwenden es sicherstellen , dass Ihr activity/fragmentwird mit @AndroidEntryPointAnmerkung auf sie.

Rahul
quelle
1

In meinem Fall war der Grund, dass ich zu früh versucht habe, eine gemeinsam genutzte Instanz des ViewModel in meinem Fragment abzurufen - bevor die Aktivität erstellt wurde. Was passiert, wenn die Anwendung nach dem Beenden ihren Status wiederherstellt?

Voraussetzungen :

  1. Mein ViewModel hat einen öffentlichen Konstruktor.
  2. Mein ViewModel hat mehrere Argumente. Dies ist jedoch absolut in Ordnung, da ich ViewModelFactory zum Erstellen des ViewModel verwende.
  3. Mein Fragment und meine Aktivität verwenden dieselbe Instanz des ViewModel . Mit anderen Worten: Aktivität erstellt das ViewModel und das Fragment erhält später dieselbe Instanz.

Code in Aktivität:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    //factory is constructed using Dagger
    val factory = App.get().components().appComponent.getMapViewModelFactory() 
    //activity creates the instance of MapViewModel
    viewModel = ViewModelProviders.of(this, factory)[MapViewModel::class.java]
}

Code in Fragment:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    //fragment receives the instance of MapViewModel
    viewModel = ViewModelProviders.of(activity!!)[MapViewModel::class.java]
    ...
}

Wenn ich die App zum ersten Mal öffne, funktioniert alles einwandfrei: Aktivität erstellt eine Instanz von ViewModel; Ich öffne Fragment, das die Instanz von ViewModel erhält. Wenn die Anwendung jedoch versucht, ihren Status nach dem Beenden wiederherzustellen, ruft sie zuerst den Hauptteil von onCreate des Fragments und dann den Hauptteil von onCreate der Aktivität auf. Zu diesem Zeitpunkt kann das Fragment das ViewModel nicht abrufen, da Activity es noch nicht erstellt hat.

Lösung 1 : Verschieben Sie den Code, wenn das Fragment das ViewModel von onCreate nach onViewCreated erhält. Dies ist in Ordnung, da ich alle Live-Daten auch in onViewCreated beobachte.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    viewModel = activity?.run { ViewModelProviders.of(this)[MapViewModel::class.java] } ?: throw Exception("Invalid Activity")

    viewModel.getSurveyDateLiveData().observe(viewLifecycleOwner, Observer<String> { dateTextView.text = it })
    ...
}

Lösung 2 : Erstellen Sie die Instanz von ViewModel in Activity.onCreate, bevor super.onCreate aufgerufen wird. In diesem Fall können Sie das ViewModel in onCreate Ihres Fragments abrufen .

override fun onCreate(savedInstanceState: Bundle?) {
    
    val factory = App.get().components().appComponent.getMapViewModelFactory()
    viewModel = ViewModelProviders.of(this, factory)[MapViewModel::class.java]
    
    super.onCreate(savedInstanceState)
    Timber.d("cc: onCreate: $this ")
}

Lösung 3 :

Wenn Sie eine Repository-Instanz in Ihr ViewModel einfügen, überprüfen Sie, ob Sie @Inject constructor(...): ViewModel()Ihr Repository nicht zum Einfügen verwenden, sondern**@ViewModelInject constructor(...): ViewModel()**

Andrew
quelle
0

In meinem Fall musste ich eine ListItemViewModelFactory verwenden, um einen Parameter an mein Ansichtsmodell zu übergeben.

Loren
quelle
0

Mein Problem war, dass die IDE meiner ViewModel-Klasse einen " abstrakten " Modifikator hinzugefügt hatte .

DBragion
quelle
0

Machen Sie die ViewModal-Klasse und die Konstruktion öffentlich

John Ruban Singh
quelle
0

Wenn der Konstruktor Ihres Ansichtsmodells öffentlich ist und nur Anwendungen akzeptiert, stellen Sie sicher, dass Sie Ihr eigenes Modell ohne erstellen können ViewModelProvider. Die Fehlermeldung ist möglicherweise viel deutlicher:

val model = YouViewModel(app)
elf
quelle
0

Ich bin ein erfahrener Android-Entwickler und habe ViewModel 100 Mal ohne Probleme verwendet. Heute bin ich auf dieses Problem gestoßen. Verbrachte Stunden und blätterte durch verschiedene SO-Beiträge. Wurde nicht gelöst.

Dann habe ich gesehen, dass der Paketname, in dem ich das ViewModel habe, enthält new. So was:

com.myapp.myfeature.new.feature

Ich newhabe newwzum Testen wie folgt gewechselt : com.myapp.myfeature.neww.feature

und es hat funktioniert! Ich hoffe, jemand findet es nützlich.

Paras Sidhu
quelle
Gut, dass es für Sie funktioniert hat, aber dies hat nichts mit ViewModels zu tun. Sie können einfach kein Schlüsselwort im Paketnamen verwenden.
Parag Kadam
Ja, Parag, aber es gab keine Warnung und Fehler deuteten nicht darauf hin. Es war nur ein zufälliges Ereignis zu entdecken, dass das Problem mit dem
Paras Sidhu
Sie könnten dieses Problem bei der Arbeit mit anderen Elementen als ViewModels entdeckt haben. Nur weil Sie dieses Problem bei der Implementierung von ViewModels entdeckt haben, ist es keine gültige Antwort auf die oben gestellte Frage.
Parag Kadam
-1

Ich verwende dieses Beispiel der Android-Arcuitecture-Komponente BasicSample , um ein neues Projekt mit einem ähnlichen Fehlerprotokoll zu erstellen, bei dem festgestellt wurde, dass ich den Anwendungsnamen nicht geändert habe

AndroidManifest.xml

und das war mein Fehler, um den Namen aplicacion in de BasicApp zu setzen, ist diese Klasse im Beispiel implementiert.

...
<application
    android:name=".BasicApp"
    android:allowBackup="false"
Sebastian Duran
quelle
-1

Bitte fügen Sie den folgenden Code hinzu. Es hat bei mir funktioniert

val binding = FragmentLayoutBinding.inflate(inflater, container, false)

val viewModel = ViewModelProvider(
            requireActivity(),
            defaultViewModelProviderFactory
            ).get(MainViewModel::class.java)
sharma_kunal
quelle