Kalianey
Kalianey

Reputation: 2798

View does not have a NavController set when using Fragment Factory and Navigation Component

I'm refactoring my app to use Fragment Factory. Everything was working fine with navigation components before the refactoring but now the fragments cannot find the Nav Controller anymore, error:

java.lang.IllegalStateException: View androidx.constraintlayout.widget.ConstraintLayout{7c24bdc V.E...... ......I. 0,0-1080,2088 #7f0a0061 app:id/auth_nav_host_fragment} does not have a NavController set
    at androidx.navigation.Navigation.findNavController(Navigation.java:84)
    at androidx.navigation.fragment.NavHostFragment.findNavController(NavHostFragment.java:118)
    at androidx.navigation.fragment.FragmentKt.findNavController(Fragment.kt:29)
    at com.kalianey.oneness.ui.auth.LauncherFragment.navLogin(LauncherFragment.kt:42)
    at com.kalianey.oneness.ui.auth.LauncherFragment.access$navLogin(LauncherFragment.kt:16)
    at com.kalianey.oneness.ui.auth.LauncherFragment$onViewCreated$1.onClick(LauncherFragment.kt:28)

I created a fragment factory:

@AuthScope
class AuthFragmentFactory
@Inject
constructor(
private val viewModelFactory: ViewModelProvider.Factory
) : FragmentFactory() {

override fun instantiate(classLoader: ClassLoader, className: String) =

    when (className) {

        OnboardingPagerFragment::class.java.name -> {
            OnboardingPagerFragment()
        }

        OnboardingOneFragment::class.java.name -> {
            OnboardingOneFragment()
        }

        OnboardingTwoFragment::class.java.name -> {
            OnboardingTwoFragment()
        }

        OnboardingThreeFragment::class.java.name -> {
            OnboardingThreeFragment()
        }

        LauncherFragment::class.java.name -> {
            LauncherFragment(viewModelFactory)
        }

        LoginFragment::class.java.name -> {
            LoginFragment(viewModelFactory)
        }

        RegisterFragment::class.java.name -> {
            RegisterFragment(viewModelFactory)
        }

        ForgotPasswordFragment::class.java.name -> {
            ForgotPasswordFragment(viewModelFactory)
        }

        else -> {
            LauncherFragment(viewModelFactory)
        }
    }

 }

Provided like this in my module:

@JvmStatic
@AuthScope
@Provides
fun provideFragmentFactory(viewModelFactory: ViewModelProvider.Factory, requestManager: RequestManager, sessionManager: SessionManager): FragmentFactory{
    return AuthFragmentFactory(viewModelFactory)
}

And I set it up like this in my AuthActivity:

override fun onCreate(savedInstanceState: Bundle?) {
    inject()
    supportFragmentManager.fragmentFactory = fragmentFactory
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_auth)
}

What am I doing wrong?

Upvotes: 0

Views: 1129

Answers (1)

Nitrodon
Nitrodon

Reputation: 3435

When you set a FragmentFactory, it's responsible for instantiating every fragment AuthActivity might need. However, when the system tries to instantiate NavHostFragment, your factory creates a LauncherFragment instead. This means you never actually created a NavHostFragment, and you don't have a NavController.

Instead of creating a LauncherFragment, your else case should create whichever fragment class was requested.

else -> {
    super.instantiate(classLoader, className)
}

Upvotes: 1

Related Questions