Navigation은 애플리케이션 내에서 화면 간 이동을 쉽게 관리할 수 있는 라이브러리이다. 네비게이션 그래프를 사용하여 화면 전환, 매개변수 전달 등을 손쉽게 관리할 수 있다. 네비게이션은 기본적으로 Jetpack Compose 기반의 네비게이션과 xml기반의 네비게이션 두 가지가 있다.
1. Jetpack Compose Navigation
Compose 기반의 네비게이션을 살펴보자
CODE
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApp {
NavigationExample()
}
}
}
}
@Composable
fun MyApp(content: @Composable () -> Unit) {
MaterialTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
content()
}
}
}
@Composable
fun NavigationExample() {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "screenA") {
composable("screenA") { ScreenA(navController) }
composable("screenB") { ScreenB(navController) }
}
}
@Composable
fun ScreenA(navController: NavHostController) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "This is Screen A", fontSize = 24.sp)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = {
navController.navigate("screenB")
}) {
Text(text = "Go to Screen B")
}
}
}
@Composable
fun ScreenB(navController: NavHostController) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "This is Screen B", fontSize = 24.sp)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = {
navController.popBackStack()
}) {
Text(text = "Back to Screen A")
}
}
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
MyApp {
NavigationExample()
}
}
선언형 기반의 컴포저블 함수를 사용하여 쉽고 가독성이 좋은 네비게이션 구성이 가능하다. 하지만 네비게이션을 컴포저블 함수로 구성하면 같은 Activity에서만 움직이기 때문에 코드 구현에 있어 한 클래스 안에 모두 구현되는 특징이 있다. 이러한 부분을 보완하기 위해 각 함수를 기능별로 나누어 클래스를 따로 두고 구조를 구현한다.
2. xml 기반의 Navigation
xml 기반의 네비게이션 구조를 살펴보자
CODE
(1) res/navigation/nav_graph.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:startDestination="@id/firstFragment">
<fragment
android:id="@+id/firstFragment"
android:name="com.example.FirstFragment"
android:label="First Fragment">
<action
android:id="@+id/action_firstFragment_to_secondFragment"
app:destination="@id/secondFragment" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.example.SecondFragment"
android:label="Second Fragment">
<action
android:id="@+id/action_secondFragment_to_firstFragment"
app:destination="@id/firstFragment" />
</fragment>
</navigation>
(2) MainActivity.kt
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupActionBarWithNavController
import com.example.R
class MainActivity : AppCompatActivity() {
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController
setupActionBarWithNavController(navController)
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
}
(3) activity_main.xml
<androidx.fragment.app.FragmentContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/nav_host_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/nav_graph"
app:defaultNavHost="true" />
xml기반의 네비게이션 구조를 만들게 되면 각 Fragment를 나누어 클래스를 구성하고 각 Fragment에 원하는 기능을 넣어 클래스를 구성할 수 있다.
3. 장단점
Compose 네비게이션의 장점
- 더 쉬운 선언적 코드: Compose 스타일로 작성하여 UI와 네비게이션을 쉽게 관리할 수 있다.
- 컴포저블 통합: 네비게이션을 다른 컴포저블들과 자연스럽게 통합할 수 있다.
- 적은 보일러플레이트 코드: XML 파일을 정의할 필요가 없다.
Compose 네비게이션의 단점
- 기존 XML 네비게이션과 호환성 문제: 기존의 XML 네비게이션 그래프를 직접 사용할 수 없다.
- 초기 학습 곡선: 새로운 개념과 API를 배우는 데 시간이 걸릴 수 있다.
XML 기반 네비게이션의 장점
- 기존 프로젝트 통합 용이: 기존의 XML 기반 네비게이션을 쉽게 통합 가능하다.
- Android Studio 지원: 네비게이션 그래프 편집기 등 툴링을 지원한다.
XML 기반 네비게이션의 단점
- 별도의 XML 파일 필요: 네비게이션을 정의하기 위해 별도의 XML 파일을 작성해야 한다.
- UI와 네비게이션 코드 분리: 선언적이지 않아 UI와 네비게이션 로직이 분리된다.
각각의 장단점에 대해서 보면 큰 차이점은 없지만 직접 사용하는 관점에서 생각해 봤을 때 컴포저블 함수에서 네비게이션을 사용하게 되면 한 컴포저블 함수를 타고 들어가 지속적으로 이어지는 컴포저블 메서드 구현을 하게 된다. 즉 지속적으로 이어지는 메서드가 생겨 마지막 단계에 있는 메서드에 데이터를 넣기 위하여 변수를 지속적으로 가지고 들어가야 하는 증상이 생기게 된다. 이는 네비게이션으로 한정 지어 보지 않아도 컴포저블 함수를 사용하게 되면 생기는 과정이지만 이러한 부분에 대하여 각 함수에 대해 클래스 별로 나누고 액티비티를 나누어야 하는 코드 구조를 갖게 된다면 xml방식을 사용하는 편이 더 좋을 수 있다.
필자는 서버에서 가져온 데이터를 가지고 각 엑티비티 별로 화면을 나누기 위하여 네비게이션은 xml네비게이션을 사용하여 화면이동을 하고 액티비티에서는 컴포저블 함수를 사용하여 UI를 구성한다. 연결하는 부분에 있어 같은 컴포저블 선언형 UI를 사용하는 것보단 유연성이 떨어지지만 아직은 네비게이션 구현에 있어 액티비티 별로 클래스를 나누는 편이 좀 더 구조에 편리한 것 같다.
'Android > Android Kotlin' 카테고리의 다른 글
[Android Kotlin] Scaffold (0) | 2024.08.02 |
---|---|
[Android Kotlin] LazyColumn (0) | 2024.08.02 |
[Android Kotlin] Compose (2-2 Ex1~2) Button, ShoppingMall (0) | 2023.11.10 |
[Android Kotlin] Compose (2-1 Ex1) 상태관리, LazyRow (0) | 2023.11.10 |
[Android Kotlin] Compose (1-2 Ex1~2) Button, AlertDialog (0) | 2023.11.10 |