java.lang.NoSuchMethodException for onCreate

Viewed 7628

I see crashes in the Google Play crash log that is really stumping me.

java.lang.RuntimeException: 
  at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3086)
  at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:3229)
  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:1926)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loop (Looper.java:214)
  at android.app.ActivityThread.main (ActivityThread.java:6981)
  at java.lang.reflect.Method.invoke (Native Method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:493)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1445)
Caused by: androidx.fragment.app.Fragment$InstantiationException: 
  at androidx.fragment.app.Fragment.instantiate (Fragment.java:462)
  at androidx.fragment.app.FragmentContainer.instantiate (FragmentContainer.java:50)
  at androidx.fragment.app.FragmentState.instantiate (FragmentState.java:80)
  at androidx.fragment.app.FragmentManagerImpl.restoreAllState (FragmentManager.java:3109)
  at androidx.fragment.app.FragmentController.restoreAllState (FragmentController.java:158)
  at androidx.fragment.app.FragmentActivity.onCreate (FragmentActivity.java:344)
  at androidx.appcompat.app.AppCompatActivity.onCreate (AppCompatActivity.java:85)
  at com.autotask.jbarra.kotlinmvvm.MainActivity.onCreate (MainActivity.kt:102)
  at android.app.Activity.performCreate (Activity.java:7326)
  at android.app.Activity.performCreate (Activity.java:7317)
  at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1271)
  at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3066)

Caused by: java.lang.NoSuchMethodException: 
  at java.lang.Class.getConstructor0 (Class.java:2328)
  at java.lang.Class.getConstructor (Class.java:1725)
  at androidx.fragment.app.Fragment.instantiate (Fragment.java:443)

the thing is, line 102 of Main activity is nothing special

    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState) //This is line 102

What could cause this? Why is oncreate throwing no such method? It's happening on a few user's devices and I haven't been able to reproduce it.

6 Answers

The activity is being restored from an instance state bundle. Part of the restore operation is recreating its fragments.

Your activity has a fragment and the fragment class does not have a 0-arg constructor required by the framework.

I'm having the same issue. The other answers did not help.

For me, it looks like it is Proguard. That explains why it only happens in production/release builds and why I have been unable to reproduce it when debugging.

If you're having OP's issue, try the following:

  1. Build the obfuscated .apk. I used the signed one, that I publish to the app stores...
  2. Enable "Don't Keep Activities" in your device's developer options.
  3. Install the .apk in your device and open the Activity that crashes and contains the Fragment.
  4. Leave your app (Minimize / Home button / ...) and re-open it from the recent apps menu.

Does it crash? Then try it with the un-obfuscated debug build. If it doesn't then it's probably Proguard.

To fix it I did the following:

  1. Create a proguard-rules.pro file in your app module's root folder.
  2. Add -keep class * extends androidx.fragment.app.Fragment{} to that file.
  3. Then, in the app's build.gradle,

add:

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

See Yaroslav Mytkalyk's answer here: Fragment Instantiation crash, which helped me solve this, although it's a bit old and outdated by now (e.g. "runProguard true" is obsolete).

At least now it doesn't crash when I do the steps above.

PS: I did this in conjunction with adding the 0-arg constructors to my fragments, as mentioned in other answers, since that was my first fixing attempt. I believe that Proguard alone was the issue and that it isn't necessary to add said constructors, but I cannot test that hypothesis now.

My Activity had a FragmentPagerAdapter that was using the deperecated constructor. I changed

class MyPagerAdapter(
        fragmentManager: FragmentManager,
        private val myActivity: MyActivity
    ) : FragmentPagerAdapter(fragmentManager) // DEPRECATED

to

class MyPagerAdapter(
        fragmentManager: FragmentManager,
        private val myActivity: MyActivity
    ) : FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)

Seem to have fixed the problem

After some search i finally fix the issue. You have to check 3 things.

  1. You should have a 0-arg constructor in the fragment, best practice is to do something like bellow
  2. If you are using callback in the caller, you have to check if getContext is null or not (otherwise you will get a NullPointerException)
  3. Don't forget to test the case when the screen orientation change, this will allow you to reproduce some potential issue due to restoring fragment state

Sample code example :

    public class MyDialogFragment extends DialogFragment{
     private String id;

     public static MyDialogFragment newInstance(String id) {
        MyDialogFragment f = new MyDialogFragment ();

        Bundle args = new Bundle();
        if(id!= null){
            args.putString("id", id);
        }
        f.setArguments(args);

        return f;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(savedInstanceState != null){
            id= savedInstanceState.getString("id");
        }
    }
    }

As already said the problem is a missing 0-arg constructor in the Fragment.
In my case the constructor was removed from a DialogFragment by the code shrinking of the release variant.

To reproduce the crash, build the app with minifyEnabled true, popup the DialogFragment and rotate the device screen.

A simple solution to keep the 0-arg constructor is to add a @Keep annotation:

public class MyDialogFragment extends DialogFragment {
    @Keep
    public MyDialogFragment() {}
}

System not able to restore your fragment due to missing zero-argument constructor for your fragment.

Adding a zero-argument constructor to all your fragment will solve error.

public YourFragment() {}
Related