118

I am facing the issue on some devices and getting an error on my crash analytics. A lot of user devices are facing this issue, but on my device it's working fine.

Unable to start activity ComponentInfo{com.ox.outloks.new/com.ox.outloks.new.activities.MainDrawerActivity}: android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.alchemative.outfitters.outfitters.fragments.ProductsFragment: could not find Fragment constructor

The error is coming at the line which is in activity super.onCreate(savedInstanceState);

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

Here is ProductsFragment constructor

@SuppressLint("ValidFragment")
public ProductsFragment(String id) {
    categoryID = id;
}
Donald Duck
  • 8,409
  • 22
  • 75
  • 99
M.ArslanKhan
  • 3,640
  • 8
  • 34
  • 56
  • 1
    What does your `ProductsFragment` class look like? Do you have any special constructors in it? – Ben P. Aug 13 '18 at 21:51
  • @BenP. I have updated my question, yes I have special constructor – M.ArslanKhan Aug 13 '18 at 21:53
  • 1
    @BenP. beat me to it. On another note, make sure you have a default empty constructor (dont override the default constructor), fragments need one. Also you should have a static method (newInstance) defined in that fragment that takes params... – Trevor Aug 13 '18 at 21:55
  • 1
    "Don't keep activities" developer setting helps replicate this issue: https://stackoverflow.com/questions/56668934/java-lang-nosuchmethodexception-for-oncreate – Weiyi Mar 15 '20 at 23:10

9 Answers9

223

All Fragment classes you create must have a public, no-arg constructor. In general, the best practice is to simply never define any constructors at all and rely on Java to generate the default constructor for you. But you could also write something like this:

public ProductsFragment() {
    // doesn't do anything special
}

If your fragment needs extra information, like String id in your posted example, a common pattern is to define a newInstance() static "factory method" that will use the arguments Bundle to give that info to your fragment.

public static ProductsFragment newInstance(String id) {
    Bundle args = new Bundle();
    args.putString("id", id);
    ProductsFragment f = new ProductsFragment();
    f.setArguments(args);
    return f;
}

Now, rather than calling new ProductsFragment(id), you'll call ProductsFragment.newInstance(id). And, inside your fragment, you can access the id by calling getArguments().getString("id").

By leveraging the arguments bundle (instead of creating a special constructor), your fragment will be able to be destroyed and recreated by the Android framework (e.g. if the user rotates their phone) and your necessary info (the id) will persist.

Ben P.
  • 52,661
  • 6
  • 95
  • 123
  • 18
    I have already done this but still, I am getting the error - Issue: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.blipclap.wallpaper/com.blipclap.wallpaper.HomeActivity}: androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment com.blipclap.wallpaper.Fragment.RecentsFragment: could not find Fragment constructor – Vinit Poojary Mar 01 '19 at 08:29
  • 7
    What if I need to pass Object variable (likely FrameLayout) as extra information ? cuz I don't see any way to put it into Bundle instance. – Tiny Angel May 21 '20 at 19:12
  • 2
    I have a fragment with no argument in constrructor and yet facing the exact problem, what can be wrong ? i probably should mention that i open my app after a while when Process Death occurred. – StackOverflower Feb 20 '23 at 14:19
12

Accepted answer is not entirely correct as of today. With FragmentFactory

you can create fragment such as

MyFragment(arg1:Any, arg2:Any,...) {

} 

and instantiate it inside FragmentFactory's instantiate method

override fun instantiate(classLoader: ClassLoader, className: String): Fragment {

        return when (className) {
            MyFragment::class.java.name -> MyFragment(arg1, arg2)
            
        }

    }

and set your FragmentFactory as supportFragmentManager's fragment factory before onCreate of Activity, because Android checks out for empty constructor fragment and if you don't provide before onCreate your app will crash as usual behavior.

supporFragmentManager.fragmentFactory = yourFragmentFactoryInstance
Thracian
  • 43,021
  • 16
  • 133
  • 222
  • This should be also accepted. You can set `supportFragmentManager.fragmentFactory` in your activity's onCreate before the `super.onCreate` call – Arrow Cen Jun 08 '22 at 00:26
6

A newer alternative to communicate between an Activity and a Fragment, thus allowing that the Fragment can have an empty constructor would be the use of ViewModels.

Alexander Pacha
  • 9,187
  • 3
  • 68
  • 108
2

Make sure the fragment class is public as well

Never_se
  • 33
  • 1
  • 7
1

I have just faced this exception. My mistake was calling requireArguments() method before arguments were received by the Fragment

Max Siomin
  • 95
  • 1
  • 7
1

The problem comes from below method of fragment class that basically shows how we should basically do initialisation of our fragment classes in general. First see that method below:-

public static Fragment instantiate(@NonNull Context context, @NonNull String fname,
        @Nullable Bundle args) {
    try {
        Class<? extends Fragment> clazz = FragmentFactory.loadFragmentClass(
                context.getClassLoader(), fname);
        Fragment f = clazz.getConstructor().newInstance();
        if (args != null) {
            args.setClassLoader(f.getClass().getClassLoader());
            f.setArguments(args);
        }
        return f;
    } catch (java.lang.InstantiationException e) {
        throw new InstantiationException("Unable to instantiate fragment " + fname
                + ": make sure class name exists, is public, and has an"
                + " empty constructor that is public", e);
    } catch (IllegalAccessException e) {
        throw new InstantiationException("Unable to instantiate fragment " + fname
                + ": make sure class name exists, is public, and has an"
                + " empty constructor that is public", e);
    } catch (NoSuchMethodException e) {
        throw new InstantiationException("Unable to instantiate fragment " + fname
                + ": could not find Fragment constructor", e);
    } catch (InvocationTargetException e) {
        throw new InstantiationException("Unable to instantiate fragment " + fname
                + ": calling Fragment constructor caused an exception", e);
    }
}

So if you will see problem lies with catch (NoSuchMethodException e) code block which triggers in this case since its not able detect contructor of the fragment from line Fragment f = clazz.getConstructor().newInstance();. If you will see the function getConstructor(), You will observe this will reponsible to make this exception since it throws this NoSuchMethodException and same have caught inside Fragment instantiate funtion. Also if you move further on above function the recommended approach for sending params to a fragment arguments is also given. So now we are all clear about what to do.

  1. To send data into fragment we should make instance/static function of that receiver fragment, and put all required params into this.
  2. Then put data using fragment arguments into receiver fragment within instance function.
  3. Finally just get those arguments into onCreate/onCreateView.

Note: This Fragment class was deprecated in API level 28. Use the Jetpack Fragment Library Fragment for consistent behavior across all devices and access to Lifecycle.

Vishal
  • 11
  • 2
1

I just putted this overrided onCreate inside Myfragment, that extends Fragment. And it works. But i think, it's kind of a plug.

@Override
public void onCreate(Bundle savedInstanceState) {
    MyFragment.newInstance();
    Bundle b = new Bundle();
    super.onCreate(b);
}
0

It can also happen if you call requireContext() method before onCreate() of the fragment.

Target
  • 35
  • 4
0

Also check your Fragment's constructor. In some cases it could be marked like private and system can't use it during restore state operation and you'll get a crash. Just use simple test with Don't keep activities option from Developer options to confirm system able to restore your fragment properly.

Djek-Grif
  • 1,391
  • 18
  • 18