#java #android #android-studio #kotlin
Вопрос:
Я использую навигационный компонент Android с нижней навигацией, lint выдает предупреждение о замене <fragment>
тега, <FragmentContainerView>
но когда я его заменил, findNavController
он не работает, это выдает мне ошибку о том, что в нем не установлен навигационный контроллер
Фрагмент
<androidx.fragment.app.FragmentContainerView
android:id="@ id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/mobile_navigation" />
Активность
val navController = findNavController(R.id.nav_host_fragment)
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_classes, R.id.navigation_schedule, R.id.navigation_settings
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
Комментарии:
1. заменить
FragmentContainerView
наfragment
2. Я не хочу использовать
fragment
, есть предупреждение, если я заменю
Ответ №1:
В соответствии с этой проблемой при использовании FragmentContainerView
вам нужно найти NavController
использование findFragmentById()
, а не использовать findNavController()
, когда в onCreate()
:
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
Это связано с тем, что findNavController(R.id.nav_host_fragment)
полагается на то, что представление фрагмента уже создано, чего не происходит при использовании FragmentContainerView
(так как FragmentTransaction
для добавления используется под капотом NavHostFragment
).
Если вы используете фрагмент 1.4.0 или выше и просматриваете привязку, вы можете значительно упростить это, используя getFragment()
метод:
val navController = binding.container.getFragment<NavHostFragment>().navController
Комментарии:
1. Да, за пределами
onCreate()
представления фрагмента будет создан, так что по-прежнему будет нормально звонитьfindNavController()
2. Этот ответ не сработал внутри
Fragment.onCreate()
. ГоворитNavController is not available before onCreate()
.3. Если вы находитесь во фрагменте, вы бы здесь ничего не использовали, вы бы использовали
NavHostFragment.findNavController(this)
/findNavController()
.4. @AdamHurwitz — да,
NavigationAdvancedSample
он использует полностью независимыеNavHostFragment
экземпляры для поддержки нескольких обратных стеков в соответствии с описанием примера ; он использует совершенно другой стиль и функциональность, отличные от любой документации.5. @Chuck — это не «волшебная переменная» — так код Kotlin ссылается на
getSupportFragmentManager()
APIFragmentActivity
.
Ответ №2:
Замените эту строку:
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
с
NavController navController = getNavController();
Где getNavController()
выглядит так:
// workaround for https://issuetracker.google.com/issues/142847973
@NonNull
private NavController getNavController() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
if (!(fragment instanceof NavHostFragment)) {
throw new IllegalStateException("Activity " this
" does not have a NavHostFragment");
}
return ((NavHostFragment) fragment).getNavController();
}
Комментарии:
1. для меня это лучшее решение
Ответ №3:
В дополнение к принятому ответу можно было бы использовать небольшой короткий путь:
supportFragmentManager.findFragmentById(R.id.navHostMain)?.findNavController()
С уважением
Ответ №4:
Добавьте в свой build.gradle (Модуль: Приложение) эту строку
implementation "androidx.navigation:navigation-fragment-ktx:2.3.2"
и используйте это в своей деятельности
val navController = supportFragmentManager.findFragmentById(R.id.your_id_nav_host_fragment)
?.findNavController()
и в отрывке
val navController = findNavController()
Ответ №5:
Я решил свою проблему с расширением:
fun FragmentActivity.findFragmentContainerNavController(@IdRes host: Int):NavController {
try {
val navHostFragment = supportFragmentManager.findFragmentById(host) as NavHostFragment
return navHostFragment.findNavController()
} catch (e: Exception) {
throw IllegalStateException("Activity $this does not have a NavController set on $host")
}
}
Ответ №6:
Есть еще более простой способ ответить @friederbluemle. Проверки утверждений должно быть достаточно.
NavHostFragment navHostFragment
= (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
assert navHostFragment != null : "navHostFragment not found";
NavController navController = navHostFragment.getNavController();
Ответ №7:
Вот простой ответ —
val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragmentContainerView)
как NavHostFragment
val navController = navHostFragment.navControllermenus.setupWithNavController(navController)
Комментарии:
1. Что это
navControllermenus
?
Ответ №8:
используйте простой <fragment>
тег вместо <androidx.fragment.app.FragmentContainerView>