[안드로이드] Navigation Component: IllegalStateException Fragment not associated with a fragment manager

Dev Hanna·2021년 6월 2일
2

안드로이드

목록 보기
6/9
post-thumbnail

안드로이드 네비게이션 컴포넌트를 이용해서 화면 이동시, 매우 드문 확률로 아래와 같은 Exception이 발생할 때가 있다.

java.lang.IllegalStateException: Fragment EarthFragment{b6e8bc7 (aa204a1e-5f3a-40c0-86f0-b5edab4b07eb)} not associated with a fragment manager.
at androidx.fragment.app.Fragment.requireFragmentManager(Fragment.java:910)
...

24시간 켜놓는 키오스크에서 몇 주에 한번 꼴로 발생하는데... 드물다면 드물고, 댓수가 많아진다 생각하면 자주라고 볼 수도 있겠다. (음...)

네비게이션으로 EarthFragment 에서 MarsFragment 로 이동하려고 할 때에 드문 확률로 EarthFragment를 참조하지 못해서 발생하는 예외로 보인다.
왜 EarthFragment를 찾지 못한고 하니, EarthFragment 에서 MarsFragment로 이미 이동을 했는데, 어떤 이유에서인지(?) MarsFragment로 한 번 더 이동을 하려고 해서 발생하는 Exception 이라는 것. 이미 화면이동이 된 후라 EarthFragment를 찾지 못한다는 것.

구글링 끝에 해결방법 찾아 적용!

// Extension 메소드를 정의하여 네비게이션 화면이동시 navigate() 대신 아래 메소드를 사용함
fun NavController.navigateSafe( 
    @IdRes resId: Int,
    args: Bundle? = null,
    navOptions: NavOptions? = null,
    navExtras: Navigator.Extras? = null
) {
    val action = currentDestination?.getAction(resId) ?: graph.getAction(resId)
    // 현재 fragment의 id와 이동할 fragment의 id가 다르면 화면이동 실행 (같다는 건, 이미 이동이 된 후이기 때문)
    if (action != null && currentDestination?.id != action.destinationId) {
        navigate(resId, args, navOptions, navExtras)
    }
}

// 이건 navigateUp() 메소드 대신에 사용
fun NavController.navigateSafeUp(@IdRes currentFragmentResId: Int) {
	// 현재 fragment 와, 인자로 받은 fragmnet의 id가 같으면 navigateUp() 실행
    if (currentDestination?.id == currentFragmentResId) {
        navigateUp()
    }
}

NavController Extension 함수를 만들어서 모든 Navigation 화면 이동시 화면 id체크 후 이동하도록 했다. 모든 화면에 다 갖다써야해서 static으로 선언함.

아래는 사용 예시.

// Example
fun moveToMarsFragment(astronaut: Person) {
	val action = EarthFragmentDirections.toMarsFragment(astronaut)
	fragment.findNavController().navigateSafe(resId = action.actionId, args = action.arguments)
}

변경 후, 더 이상 이슈가 발생하지 않았다.

이럴 때 참 뿌듯.

profile
오늘도 1보 걷기

0개의 댓글