Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling Fragment constructor caused an exception. Navigation Architecture Component

I am using navigation architecture component library and my app's starting point is this fragment:

class MainFragment : BaseFragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_main, container, false)
    }

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

Which inherits from an abstract class which is BaseFragment:

abstract class BaseFragment : Fragment() {

}

When I run my app I get:

 Unable to instantiate fragment io.example.MainFragment: calling Fragment constructor caused an exception

But this does not happen if MainFragment extends Fragment instead of BaseFragment. What is the reason? Does this have something to do with how the Navigation Architecture Component works?

like image 264
Mostafa Avatar asked Jan 05 '19 09:01

Mostafa


3 Answers

I had the similar issue because I had val in MyBaseFragment

protected abstract val gpsMsg: String

which I was overiding this way in other Fragment before fragment attached to context.

override val gpsMsg: String = getString(R.string.gps_not_enabled)

So the underlying error was because context was null and getString uses getResources() which returns requireContext().getResources(). And in the requireContext() source code error will be thrown.

public final Context requireContext() {
    Context context = getContext();
    if (context == null) {
        throw new IllegalStateException("Fragment " + this + " not attached to a context.");
    }
    return context;
}

So the error thrown causes fragment not to be instantiated. So I would advice being careful with context thing when override.

like image 179
Nux Avatar answered Oct 12 '22 18:10

Nux


I faced similar issues for a while now. In order to fix the issue, do not use a context related resource before context is initialized.

For example, in case you are using getString() method (context related resource) to access a string value, do use it always in the onViewCreated() method of fragment.

This ensures the context is initialized and thus can be access.

Hope this helps!

like image 44
Besong-Anong Ernest Avatar answered Oct 12 '22 17:10

Besong-Anong Ernest


I had the same error and none of the above answers helped me because it was actually a different mistake I had made.

class RunFragment : Fragment() {
private lateinit var runViewModel: RunViewModel
    var calories= String.format("%.2f",runViewModel.calories)
    var distanceTravelled= String.format("%.2f",runViewModel.distanceTravelled)
    var stepsRun= String.format("%.2f",runViewModel.stepsRun)
}

before onCreateView

my runViewModelhad not yet been instantiated since it was lateinit but I was already referring to it. Changing it to this below solved the problem

private lateinit var runViewModel: RunViewModel
    var calories= ""
    var distanceTravelled= ""
    var stepsRun= ""

 override fun onCreateView(.......): View? {

        calories= String.format("%.2f",runViewModel.calories)
        distanceTravelled= String.format("%.2f",runViewModel.distanceTravelled)
        stepsRun= String.format("%.2f",runViewModel.stepsRun)
}
like image 2
pokumars Avatar answered Oct 12 '22 19:10

pokumars