-1

Recently I wrote a simple Android App.

The App has a simple MainActivity and a ViewModel. While writing the code I did declare the ViewModel class to be public.

Just before I finished the app I went over warnings and saw one saying that the access modifier of the ViewModel class can become package instead of public.

At the time I did not give it much thought and removed the public modifier.

I tested the app and everything worked fine.

I then made a release build and the app crashed upon startup. I did not make the connection to why this happened but from a quick look at the stack trace, I got it. I added the public modifier back to the ViewModel class and everything was working as it should.

Since the ViewModel is actually instantiated by the provider that is outside of my package the ViewModel have to have a public modifier.

My question is why did my app work properly in Debug compilation configuration as I would expect it to crash there too...

My ViewModel:

import android.app.Application;
import android.util.Log;

import androidx.lifecycle.AndroidViewModel;

import java.util.ArrayList;
import java.util.Random;

public class TilesViewModel extends AndroidViewModel {

My createtion of the ViewModel:

mViewModel = ViewModelProviders.of(this).get(TilesViewModel.class);

Crash:

 Caused by: java.lang.RuntimeException: Cannot create an instance of class il.co.woo.karuba.TilesViewModel
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:234)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:164)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:130)
        at il.co.woo.karuba.MainActivity.onCreate(MainActivity.java:70)
        at android.app.Activity.performCreate(Activity.java:6679)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) 
        at android.app.ActivityThread.-wrap12(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:154) 
        at android.app.ActivityThread.main(ActivityThread.java:6119) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 
     Caused by: java.lang.IllegalAccessException: java.lang.Class<il.co.woo.karuba.TilesViewModel> is not accessible from java.lang.Class<androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory>
        at java.lang.reflect.Constructor.newInstance0(Native Method)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:430)
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:230)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:164) 
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:130) 
        at il.co.woo.karuba.MainActivity.onCreate(MainActivity.java:70) 
        at android.app.Activity.performCreate(Activity.java:6679) 
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726) 
        at android.app.ActivityThread.-wrap12(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:154) 
        at android.app.ActivityThread.main(ActivityThread.java:6119) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 
Itamar Kerbel
  • 2,508
  • 1
  • 22
  • 29

1 Answers1

0

There are many reasons related to ViewModel creation for example.

  1. You are not using public access modifier for the class or constructor and factory might not be able to create an instance of it.
  2. you are extending the wrong ViewModel
  3. ViewModel parameterized constructors may also create problems due to unable to create other injected objects in constructor.

But in your case which is working in Debug and not in Release is may be due to Proguard which may be truncating the access modifiers or constructors unused which might be causing this problem.

Reference discussion

vikas kumar
  • 10,447
  • 2
  • 46
  • 52
  • I understand what you are saying about ProGuard but it feels the other way around as I was the one who removed the public modifier in the first place I would expect it to crash with or without ProGuard as how would Android instantiate my ViewModel... – Itamar Kerbel Jul 15 '19 at 08:06