제목과 같이 navigation 라이브러리를 활용하며 FragmentContainerView를 쓰고 있는데 navigation graph과 startDestination를 갈아끼워야 했다. 우선 의도대로 동작하는 줄 알았던 코드를 보자.
override fun initView() {
super.initView()
setNavigation()
initNavigation()
setNavigationBackListener()
}
private fun setNavigation() {
val navHostFragment =
supportFragmentManager.findFragmentById(binding.commonDetailHostFragment.id) as NavHostFragment
navController = navHostFragment.navController
}
private fun initNavigation() {
val initialFragment = getInitialFragment()
val navigation = intent.getIntExtra("navigationId", R.navigation.my_detail_nav_graph)
val navGraph = navController.navInflater.inflate(navigation)
navGraph.setStartDestination(initialFragment.id)
navController.graph = navGraph
}
private fun getInitialFragment(): NavDestination {
val fragmentId = intent.getIntExtra("fragmentId", R.id.membershipFragment)
return navController.graph.findNode(fragmentId)
?: navController.graph.findStartDestination()
}
private fun setNavigationBackListener() {
binding.commonDetailToolbar.detailBacKBtn.setOnClickListener {
if (navController.backQueue.size == 2) {
finish()
} else {
navController.popBackStack()
}
}
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
intent로 특정 값을 받아오고, 그 값에 따라서 FragmentContainerView에 navigation graph를 갈아끼우고, 또 그 그래프에서 처음 띄울 fragment(startDestination)을 제어하는 코드다.
잘 동작하는 줄 알았다. 이 코드의 default 값인 navigation graph를 끼워넣을 때는..
그러나 위 코드는 다양한 navigation graph를 넣었을 때
💡 java.lang.RuntimeException: Unable to start activity ComponentInfo{~~~~~~~.widget.CommonDetailActivity}: java.lang.IllegalArgumentException: navigation destination 2131230843 is not a direct child of this NavGraph이런 오류가 뜨면서 제대로 동작하지 않는다. navigation graph가 제대로 적용되지 않았기 때문.
그래서 아래처럼 네비게이션 초기화 함수를 바꿔봤는데 무조건 startDestination을 반환했다.
private fun initNavigation() {
val navigation = intent.getIntExtra("navigationId", R.navigation.my_detail_nav_graph)
val navGraph = navController.navInflater.inflate(navigation)
navController.graph = navGraph
val initialFragment = getInitialFragment()
navGraph.setStartDestination(initialFragment.id)
}
private fun initNavigation() {
val initialFragmentId = intent.getIntExtra("fragmentId", R.id.membershipFragment)
val navigation = intent.getIntExtra("navigationId", R.navigation.my_detail_nav_graph)
val navGraph = navController.navInflater.inflate(navigation)
val startDestination = getStartDestination(navGraph, initialFragmentId)
navGraph.setStartDestination(startDestination)
navController.graph = navGraph
}
private fun getStartDestination(navGraph: NavGraph, fragmentId: Int): Int {
return navGraph.findNode(fragmentId)?.id ?: navGraph.findStartDestination().id
}
그냥.. 코딩 아무 생각 없이 해서 생긴 문제^^;
공통 액티비티로 활용하고 재활용할 수 있게 만든 코드라서 전체 코드도 올려둔다. navController와 같이 선언되지 않은 것들은 BaseAcitivity에 있다~
@AndroidEntryPoint
class CommonDetailActivity :
BaseActivity<ActivityCommonDetailBinding>(ActivityCommonDetailBinding::inflate) {
private val toolbarStateViewModel: ToolbarStateViewModel by viewModels()
override fun initView() {
super.initView()
setNavigation()
initNavigation()
setNavigationBackListener()
this.onBackPressedDispatcher.addCallback(this, backPressedCallback)
}
private fun setNavigation() {
val navHostFragment =
supportFragmentManager.findFragmentById(binding.commonDetailHostFragment.id) as NavHostFragment
navController = navHostFragment.navController
}
private fun initNavigation() {
val initialFragmentId = intent.getIntExtra("fragmentId", R.id.membershipFragment)
val navigation = intent.getIntExtra("navigationId", R.navigation.my_detail_nav_graph)
val navGraph = navController.navInflater.inflate(navigation)
val startDestination = getStartDestination(navGraph, initialFragmentId)
navGraph.setStartDestination(startDestination)
navController.graph = navGraph
}
private fun getStartDestination(navGraph: NavGraph, fragmentId: Int): Int {
return navGraph.findNode(fragmentId)?.id ?: navGraph.findStartDestination().id
}
private fun setNavigationBackListener() {
binding.commonDetailToolbar.detailBacKBtn.setOnClickListener {
setBackInteraction()
}
}
private val backPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
setBackInteraction()
}
}
private fun setBackInteraction() {
if (navController.backQueue.size == 2) {
finish()
} else {
navController.popBackStack()
}
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
override fun setObserver() {
super.setObserver()
toolbarStateViewModel.detailToolbarTitle.observe(this) { title ->
binding.commonDetailToolbar.detailTitle.text = title
}
}
}