https://developer.android.com/guide/navigation/navigation-getting-started?hl=ko
kotlin-android-extensions deprecated
'kotlin-android-extensions'
- 기존에 extensions를 사용하였다면 kotlin-android-extensions에서 제공하는 kotlin synthetics를 사용하여 선언하였기에 Databinding or ViewBinding 없이 전역변수(xml)에 접근할 수 있었다.
- 또한, 오래된 <fragment> 대신에 구글에서 권장하는 <FragmentContainerView>를 사용한다.
Jetpack Navigation 연동
- dependencies 추가
// Navigation Components
implementation("androidx.navigation:navigation-fragment-ktx:2.3.5")
implementation("androidx.navigation:navigation-ui-ktx:2.3.5")
- nav_graph.xml 추가
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nav_graph"
app:startDestination="@id/searchSummonerFragment">
...
</navigaton>
- Project 창에서 res 디렉터리를 마우스 오른쪽 버튼으로 클릭하고 New > Android Resource File을 선택합니다. New Resource File 대화상자가 나타납니다.
- File name 필드에 'nav_graph'와 같은 이름을 입력합니다
- Resource type 드롭다운 목록에서 Navigation을 선택하고 OK를 클릭합니다.
nav_graph에 destination(fragment) 추가
- 탐색 편집기에서 New Destination 아이콘 을 클릭한 다음 Create new destination을 클릭합니다.
- New Android Component 대화상자가 표시되면 프래그먼트를 만듭니다.
- xml에 navHost 추가
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/bottomNavigationView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/appBarLayout"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph"
>
위처럼 navigation이 활동할 FragmentContainerView를 선언해주고,
- android:name 속성은 NavHost 구현의 클래스 이름을 포함합니다.
- app:navGraph 속성은 NavHostFragment를 탐색 그래프와 연결합니다. 탐색 그래프는 사용자가 이동할 수 있는 이 NavHostFragment의 모든 대상을 지정합니다.
- app:defaultNavHost="true" 속성을 사용하면 NavHostFragment가 시스템 뒤로 버튼을 가로챕니다. 하나의 NavHost만 기본값으로 지정할 수 있습니다. 동일한 레이아웃에 여러 호스트가 있다면(예: 창이 2개인 레이아웃) 한 호스트만 기본 NavHost로 지정해야 합니다.
에러 발생 코드
binding.bottomNavigationView.setupWithNavController(binding.navHostFragment.findNavController())
이렇게 bottomNavigationView에 NavHost를 연결시키니
java.lang.IllegalStateException: View androidx.fragment.app.FragmentContainerView{64699eb V.E...... ......I. 0,0-0,0 #7f080132 app:id/nav_host_fragment} does not have a NavController set
오류가 발생했다.
binding으로 불러온 FragmentContainerView에서 NavController를 찾는게 실패한 것 같다.
따라서 아래 코드로 Type casting을 시도했다.
val navHostFragment = binding.navHostFragment as NavHostFragment
val navController = navHostFragment.navController
binding.bottomNavigationView.setupWithNavController(navController)
어림없다. 이번엔 cast 오류다
Caused by: java.lang.ClassCastException: androidx.fragment.app.FragmentContainerView cannot be cast to androidx.navigation.fragment.NavHostFragment
제대로 구글 가이드를 읽어보니,
우리는 FragmentContainerView를 사용하여 NavHostFragment를 만들었다.
위와 같이 supportFragmentManager에서 findFragmentById를 사용해 직접 해당 FragmentContainerView를 검색해서 해당 View가 지닌 Class속성인 navHostFragment로 TypeCasting을 해야 가져올 수 있다.
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
binding.bottomNavigationView.setupWithNavController(navController)
해결