본문 바로가기
Android Jetpack Compose/Navigation, Route

다른 Origin 에서 들어오는 route 에 대한 처리 방법 # Jetpack Compose Navigation

by Developer88 2023. 4. 27.
반응형

오늘은 각각 다른 origin(출발지)에서 공유되는 Screen 으로 route가 들어오는 경우,

그것의 처리 방법에 대해서 정리해 보도록 하겠습니다.

 

1. 큰 그림

각각 다른 Origin에서 들어오는 경우의 생각해야 할 문제점은,

다른 UI에서 각각 다른 데이터를 들고 들어온다는 것 입니다.

이것은 origin 별로 다르게 데이터를 처리해서 보여주어야 한다는 것을 의미합니다.

 

이 문제를 해결하기 위한 방법은 여러가지이겠지만,

다음과 같은 방법이 있을 수 있겠네요.

우선은 isFromXXOrigin 이라는 boolean 을 route의 argument 로 받아서,

그것을 보고 각기 다르게 처리하는 방식이구요.

다른 하나는 Sealed Class를 사용해서 route를 구분해서 받는 것 입니다.

  • isFromXXOrigin argument 값을 받아서 보고 처리
  • NavigationEvent Sealed Class를 만들어서 route들을 선언해서 사용
    • 어떤 Event에서 온 것인지 라우트를 보고 처리

 

 

첫 번째 방법이 구현하기 훨씬 쉽다고 할 수 있구요.

Sealed Class를 사용하는 방법은 좀 더 유연하고 확장성 있다고 할 수 있습니다.

나중에 공유되는 페이지로 들어오는 origin이 늘어나더라도 쉽게 대응할 수 있으니까요.

 

이 글에서는 두 번째 Sealed Class를 사용하는 방법에 대해서 정리해 보도록 하겠습니다.

 

2. SealedClass 로 다른 Route 정의하기

먼저 할일은 각각의 다른 Origin에서 나오는 route 를 정의하는 것 입니다.

여기서는 아래와 같이 2가지의 NavigationEvent를 정의하였습니다.

route에 data를 전달할 때, 사용할 util함수로 generate Route라는 함수를 포함시켰습니다.

values()는 NavEvent 를 묶어서 반복문으로 한번에 전달하기 위해서,

companion object에 추가해 주었습니다.

 

generateRoute의 인자로 Map타입을 사용한 이유는,

이 글에서는 데이터를 1개만 넘기고 있지만,

나중에 인자로 데이터들을 전달할 때,

여러개의 데이터를 넘기는 경우도 있을 수 있으니 그렇게 하였습니다.

 

sealed class NavEvent {
    abstract val route: String
	abstract val arguments: List<NamedNavArgument>

    object FromFirstPage : NavEvent() {
        override val route: String = "third_page/from_first_page/{data}"
        override val arguments: List<NamedNavArgument>
    }

    object FromSecondPage : NavEvent() {
        override val route: String = "third_page/from_second_page/{id}"
        override val arguments: List<NamedNavArgument>
    }

    fun generateRoutes(argumentsMap: Map<String, Any>): String {
        var resultRoute = route
        argumentsMap.forEach { (key, value) ->
            resultRoute = resultRoute.replace("{$key}", value.toString())
        }
        return resultRoute
    }
        
    companion object {
        fun values() = listOf(FromFirstPage, FromSecondPage)
    }       
}

 

 

3. Navigation 정의

이제 Navigation의 컨테이너인 NavHost에 Navigation을 정의해서 사용해 보겠습니다.

위에서 Companion Object 에 정의했던, values()함수를 이용해서, 

반복문으로 navEvent들을 가져옵니다.

 

val navController = rememberNavController()

NavHost(navController, startDestination = "first_page") {
        composable("first_page") {
            FirstPage(navController)
        }
        composable("second_page") {
            SecondPage(navController)
        }
        NavEvent.values().forEach { navEvent ->
            composable(
                route = navEvent.route,
                arguments = navEvent.navArguments
            ) { backStackEntry ->
                val id = backStackEntry.arguments?.getInt("id")
                ThirdPage(navEvent)
            }
        }    	        
}

 

이렇게 해서 각각 다른 origin 으로부터 공유되는 Page에 대해서 처리를 할 수 있게 되었습니다.

 

3. Composable 정의

위의 Event 를 사용할 각각의 페이지들을 정의해 줍니다.

간단하게 Button을 누르면, 값을 넘겨주고 실행되도록 하였습니다.

 

@Composable
fun FirstPage(navController: NavController) {
    Column {
        Text("여기는 First Page")
        Button(onClick = { 
        	navController.navigate(
                NavEvent.FromFirstPage.generateRoutes(mapOf("id" to 1))
            )
        }) {
            Text("Second Page로 이동")
        }
    }
}

@Composable
fun SecondPage(navController: NavController) {
    Column {
        Text("여기는 Second Page")
        Button(onClick = { 
			navController.navigate(
                NavEvent.FromSecondPage.generateRoutes(mapOf("id" to 2)))
            Text("Third Page로 이동")
        }
    }
}

 

 

그럼 이제 first와 second에서 도착하게 될, thirdPage 만 만들어주면 되겠습니다.

각각의 페이지별로 다른 데이터를 받은 것을 볼 수 있습니다.

 

@Composable
fun ThirdPage(navEvent: NavEvent) {
    when (navEvent) {
        is NavEvent.FromFirstPage -> {
            //여기서는 String 타입의 data를 받음
            val data = navEvent.data
		}
        is NavEvent.FromSecondPage -> {
            // 여기서는 Int 타입의 id 값을 받음
            val id = navEvent.id
        }
    }
    Column {
        Text("Third Page")
        Text("들어오는 페이지별로 다른 데이터를 받았음")
    }
}

 

위에서는 ThirdPage에서 NavEvent를 받아서 구분하여 처리하였지만,

arguments에 route를 추가해서,

viewModel에서 route를 보고 처리할 수 있도록 해도 될 것 같습니다.

참고로 ViewModel에서 argument를 받는 방법은 아래 글을 참조해 주세요.

>> Route 에서 전달된 값을 ViewModel 에서 받는 방법 # Jetpack Compose Navigaion savedStateHandle

728x90

댓글