0

I'm doing this inside my onCreate method of MainActivity

journalViewModel = new ViewModelProvider(this).get(JournalViewModel.class);

and my ViewModel is as following:

public class JournalViewModel extends AndroidViewModel {

    public JournalViewModel(@NonNull Application application) {
        super(application);
        repository = new JournalRepository(application);
        journals = repository.getAllJournals();
    }
}

However, I'm getting the error for this line,

journalViewModel = new ViewModelProvider(this).get(JournalViewModel.class);

saying,

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.diaryapp/com.example.diaryapp.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.example.diaryapp.JournalViewModel

As per my knowledge the constructor inside ViewModel shouldn't have any other parameter except the one in my code and both constructor and class should be public.

However, further inside my error logs, I get the error:

java.lang.InstantiationException: java.lang.Class<com.example.diaryapp.JournalViewModel> has no zero argument constructor

Here's the complete error log:

2020-03-23 21:37:18.986 8632-8632/com.example.diaryapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.diaryapp, PID: 8632
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.diaryapp/com.example.diaryapp.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.example.diaryapp.JournalViewModel
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2946)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3081)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1831)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:201)
    at android.app.ActivityThread.main(ActivityThread.java:6823)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
 Caused by: java.lang.RuntimeException: Cannot create an instance of class com.example.diaryapp.JournalViewModel
    at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:221)
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187)
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
    at com.example.diaryapp.MainActivity.onCreate(MainActivity.java:40)
    at android.app.Activity.performCreate(Activity.java:7224)
    at android.app.Activity.performCreate(Activity.java:7213)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1272)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2926)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3081) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1831) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:201) 
    at android.app.ActivityThread.main(ActivityThread.java:6823) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873) 
 Caused by: java.lang.InstantiationException: java.lang.Class<com.example.diaryapp.JournalViewModel> has no zero argument constructor
    at java.lang.Class.newInstance(Native Method)
    at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:219)
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187) 
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150) 
    at com.example.diaryapp.MainActivity.onCreate(MainActivity.java:40) 
    at android.app.Activity.performCreate(Activity.java:7224) 
    at android.app.Activity.performCreate(Activity.java:7213) 
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1272) 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2926) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3081) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1831) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:201) 
    at android.app.ActivityThread.main(ActivityThread.java:6823) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873) 
dkhost07
  • 312
  • 1
  • 4
  • 17
  • 2
    As you can see from your log: `java.lang.Class has no zero argument constructor` Just provide the default constructor and that'll solve the issue. – Vucko Mar 23 '20 at 16:27
  • @Vucko, I already tried that. Default constructor can't be provided as there's only one constructor inside superclass `AndroidViewModel` which is with the `Application` param. – dkhost07 Mar 23 '20 at 16:33
  • 2
    `ViewModelProvider` creates a default `ViewModelProvider.Factory`, which will instantiate view models with reflection, but only it expects to find a zero-arg constructor. The solution is to either get rid of your constructor parameter like @Vucko said, or create your own `ViewModelProvider.Factory`. – Nicolas Mar 23 '20 at 16:33
  • @dkhost07 Don't use AndroidViewModel, use ViewModel. – Nicolas Mar 23 '20 at 16:33
  • @Nicolas, So, there's no other way to do it without using `Factory`? – dkhost07 Mar 23 '20 at 16:35
  • @dkhost07 Providing your own factory is pretty usual, most apps do it. – Nicolas Mar 23 '20 at 16:35
  • Can't you pass the singleton Application class in there without the param? – Vucko Mar 23 '20 at 16:55
  • 1
    you have to create view model instance through factory method – Abdul Mar 23 '20 at 17:36
  • I used `ViewModelProvider.NewInstanceFactory` as the superclass for a Factory class I created myself and updated it accordingly inside the `ViewModelProvider` constructor. It works now. Thanks to those who replied. I've posted the working solution – dkhost07 Mar 23 '20 at 18:14

3 Answers3

2

You should obtain JournalViewModel like:

journalViewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication())).get(JournalViewModel.class);  

instead of

journalViewModel = new ViewModelProvider(this).get(JournalViewModel.class);
Asad Mahmood
  • 532
  • 1
  • 5
  • 15
1

Not sure about Java, but this worked for me in Kotlin.

You need to define a ViewModelProvidor.Factory:

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    viewModelFactory.setApplication(application)
    val journalViewModel = ViewModelProvider(this, viewModelFactory).get(JournalViewModel::class.java)
    }
}

object viewModelFactory : ViewModelProvider.Factory {
    lateinit var app : Application

    fun setApplication(application: Application) {
        app = application
    }
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return JournalViewModel(app) as T
    }

}
Cory Roy
  • 5,379
  • 2
  • 28
  • 47
0

I got it working with the help of this answer.

Here's what I did in,

JournalFactory.java

public class JournalFactory extends ViewModelProvider.NewInstanceFactory {
    private Application application;

    public JournalFactory(@NonNull Application application) {
        this.application = application;
    }

    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        if (modelClass == JournalViewModel.class)
            return (T) new JournalViewModel(application);
        return null;
    }
}

onCreate() method of MainActivity.java

journalViewModel = new ViewModelProvider(this, new JournalFactory(getApplication())).get(JournalViewModel.class);
dkhost07
  • 312
  • 1
  • 4
  • 17