class FragmentProviderFactory @Inject constructor(
private val providers: Map<Class<out Fragment>, @JvmSuppressWildcards Provider<Fragment>>
) : FragmentFactory() {
override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
val fragmentClass = loadFragmentClass(classLoader, className)
val provider = providers[fragmentClass] ?:
providers.asIterable().firstOrNull(){
fragmentClass.isAssignableFrom(it.key)
}?.value ?: throw IllegalArgumentException("unknown fragment class $fragmentClass")
return try {
provider.get()
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
@Module
abstract class MainFragmentModule {
@MainScope
@Binds
@IntoMap
@FragmentKey(NotificationFragment::class)
abstract fun provideNotificationFragment(fragment: NotificationFragment): Fragment
@MainScope
@Binds
abstract fun bindFragmentProviderFactory(
fragmentProviderFactory: FragmentProviderFactory
): FragmentFactory
}
@MainScope
@Subcomponent(
modules = [MainModule::class, MainFragmentModule::class, MainViewModelModule::class]
)
interface MainComponent {
fun inject(activity: MainActivity)
}
class MainActivity : AppCompatActivity() {
@Inject lateinit var fragmentProviderFactory: FragmentProviderFactory
override fun onCreate(savedInstanceState: Bundle?) {
(applicationContext as MyApplication).appComponent.mainComponent().inject(this)
supportFragmentManager.fragmentFactory = fragmentProviderFactory
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
class NotificationFragment @Inject
constructor(provider: Provider<MainViewModel>,
private val fragmentFactory: FragmentProviderFactory): NavHostFragment() {
private val mainViewModel: MainViewModel by activityViewModelWithProvider {
provider.get()
}
private val DIALOG_FRAGMENT = 1
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_notification, container, false)
return view.rootView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btn_start.setOnClickListener{
val action = NotificationFragmentDirections.actionNotificationFragmentToNotificationDialogFragment()
navController.navigate(action)
}
}
}
Теперь этот код выше работает для рендеринга фактического фрагмента NotificationFragment, но когда я пытаюсь перейти с действием в OnClickListener моего btn, текущий узел навигации отсутствует. Я уверен, что мне нужно связать навигационный график с этим NavHostFragment. Моя XML для MainActivity выглядит следующим образом:
<fragment
android:id="@+id/nav_host_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.gcgsauce.notify.ui.NotificationFragment"/>
Если я попытаюсь добавить (app: defaultNavHost = "true" и app: navGraph = "@ navigation / nav_main") к этому, я буду получить ошибку переполнения стека. Если я пытаюсь добавить его в фактический фрагмент NotificationFragment (который расширяет NavHostFragment):
override fun onCreateNavController(navController: NavController) {
super.onCreateNavController(navController)
navController.graph = (navController.navInflater).inflate(R.navigation.nav_main)
}
, я получаю ту же ошибку (также пытался установить график в OnViewCreated). Подробности ошибки StackOverflow следующие:
![There is some kind of infinite loop when checking for menus and isMenuAvailable when associating a NavGraph](https://i.stack.imgur.com/QJqNT.png)