- Navigation Component
Navigating์ ๋ค๋ฅธ ํ๋ฉด์ผ๋ก ์ด๋ํ๋ค๋ ๊ฒ์ ๋ปํ๋ค.
Android ๊ฐ๋ฐ์ ์์ด์ ํ์์ ์ธ ๊ธฐ๋ณธ ์์์ผ ๊ฒ์ด๋ค.
Jetpack๊ณผ ํจ๊ป ์๊ฐ๋ Navigation Component๋ ์ด๋ฌํ App ๋ด์ ํ๋ฉด์ด๋ ํ๋ฆ์ ๊ทธ๋ํ๋ก ์ง์ ํ์ฌ
๋ง์น ๋ค๋น๊ฒ์ด์
์ฒ๋ผ ๋์ํ๋ค.
- ์ผ๋ฐ์ ์ธ ์๋๋ก์ด๋ ํ๋ฉด์ด๋์ ๋ํ ๋จ์ํ ์ค์
- ํ๋จ ํ์ ๋ฑ
- ๋ฐฑ ์คํ ์ฒ๋ฆฌ ์์
- ํธ๋์ญ์ ์ฒ๋ฆฌ ์์
- ํ๋ฉด ๊ฐ Type Safe ํ Arguments ์ ๋ฌ
- Transition animation ์ฒ๋ฆฌ
- ๊ฐ๋จํ ๋ฅ ๋งํน
- ๋ชจ๋ Navigation ์ ๋ณด๋ฅผ ๋ชจ์ผ๊ณ , ์๊ฐํ๋ ๊ทธ๋ํ๋ก ๋ณผ ์ ์์
Navigaion Component์ ํน์ง์ค ํ๋๋ ์ธ ์๊ธฐ ์ค์ํ ๋ถ๋ถ์ด ์กฐํ๋กญ๊ฒ ์๋๋๋ค๋ ๊ฒ
- Navigation graph
- NavHostFragment
- NavController
Navigation graph๋ ์๋ก์ด Android resource ์ ํ์ผ๋ก,
xml ํ์ผ ํํ๋ก ํ๋ฉด ํ์์ ๊ด๋ จ๋ ์ ๋ณด๋ฅผ ํฌํจํ๋ฉฐ, ์ค์ฌํ ํ๋ค.

๊ทธ๋ํ๋ด์์ ์๊ฐ์ ์ผ๋ก ํ์๋๋ ํ๋ฉด๋ค์ ๋ชฉ์ ์ง(Destination)์ด๋ผ ๋ถ๋ฆฐ๋ค.
Destination์ ํด๋ฆญํ๋ฉด ๋ฅ๋งํฌ URL ๋ฑ์ ๋ณผ ์ ์๋ค.
๊ทธ๋ํ๋ด์ ํ์ดํ๋ ์ก์
์ด๋ผ ๋ถ๋ฅธ๋ค. ์ฑ์ ํตํ์ฌ ์ฌ์ฉ์๊ฐ ์ด๋ํ ์ ์๋ ๋ค์ํ ๊ฒฝ๋ก๋ฅผ ๋ํ๋ธ๋ค.
๊ทธ๋ํ ๋ด์ ์ก์
์ ํด๋ฆญํ๋ฉด arguments, transaction, animation, backstack ์กฐ์ ๋ฑ ๋ชจ๋ ์ ๋ณด๋ฅผ ๋ณผ ์ ์๋ค.
<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"
app:startDestination="@+id/home_dest">
<!-- ...tags for fragments and activities here -->
</navigation><navigation>์ ๋ชจ๋ ํ์ ๊ทธ๋ํ์ ๋ฃจํธ ๋ ธ๋์ด๋ค<navigation>์๋<activity>๋๋<fragment>์์๋ก ํ์๋ ๋์์ด ํ๋ ์ด์ ํฌํจ๋๋คapp:startDestination์ ์ฌ์ฉ์๊ฐ ์ฑ์ ์ฒ์ ์ด ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์คํ๋๋ ๋์์ ์ง์ ํ๋ ์์ฑ์ด๋ค
<navigation> ์์ <fragment> ์์์ ๋ํ์ฌ ์ดํด๋ณด์
<fragment
android:id="@+id/flow_step_one_dest"
android:name="com.sample.navigation.FlowStepFragment"
tools:layout="@layout/flow_step_one_fragment">
<argument
.../>
<action
android:id="@+id/next_action"
app:destination="@+id/flow_step_two_dest">
</action>
</fragment>android:id๋ ์ด XML ๋ฐ ์ฝ๋์ ๋ค๋ฅธ ์์น์์ ๋์์ ์ฐธ์กฐํ๋ ๋ฐ ์ฌ์ฉํ ์ ์๋ ํ๋๊ทธ๋จผํธ์ ID๋ฅผ ์ ์ํ๋คandroid:name์ ๋์์ผ๋ก ์ด๋ํ ๋ ์ธ์คํด์คํํ ํ๋๊ทธ๋จผํธ์ ์ ๊ทํ๋ ํด๋์ค ์ด๋ฆ์ ์ ์ธํ๋คtools:layout์ ๊ทธ๋ํฝ ํธ์ง๊ธฐ์์ ํ์ํด์ผ ํ๋ ๋ ์ด์์์ ์ง์ ํ๋ค
NavHostFragment๋ Fragment๋ฅผ ์์ํ๊ณ ์์ผ๋ฉฐ, NavHost ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ค.
NavHostFragment๋ ๋ณดํต FragmentContainerView์ ์ฌ์ฉํ๋ฉฐ,
ํ๋ฉด์ด๋์ด ๋ฐ์ํ๋๋ก ๋ ์ด์์ ๋ด์ ํ๋ฉด์ ๋ณด์ฌ์ฃผ๋ ์์ญ์ ์ ๊ณตํ๋ค.
NavHostFragment๋ ๊ฐ๋ณ์ ์ผ๋ก NavController๋ฅผ ๊ฐ์ง๋ค.
<androidx.fragment.app.FragmentContainerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/nav_sample"
app:defaultNavHost="true" />android:name์์ฑ์ NavHost ๊ตฌํ์ ํด๋์ค์ด๋ฆ์ ๋ฃ๋๋คapp:navGraph์์ฑ์ NavHostFragment๋ฅผ ๊ทธ๋ํ์ ์ฐ๊ฒฐํ๋คapp:defaultNavHost="true"์์ฑ์ ์ฌ์ฉํ๋ฉด NavHostFragment๊ฐ ์์คํ ๋ค๋ก ๋ฒํผ์ ๊ฐ๋ก์ฑ๋ค- ํ๋์ NavHost๋ง ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ง์ ํ ์ ์๋ค
- ๋์ผํ ๋ ์ด์์์ ์ฌ๋ฌ ํธ์คํธ๊ฐ ์๋ค๋ฉด ํ ํธ์คํธ๋ง ๊ธฐ๋ณธ NavHost๋ก ์ง์ ํด์ผ ํ๋ค
NavController๋ ํ๋ฉด์ด ์ด๋๋๋ Navigation์ ์ฒ๋ฆฌํ๋ค. NavController๋ Graph๋ด์ ์ ์๋ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก Kotlin์ฝ๋ ๋ด์์ ํ๋ฉด ์ด๋์ ์ฒ๋ฆฌํ๋ค.
findNavController().navigate(R.id.win_action)- Options Menus
- Bottom Navigation
- Navigation View
- Navigation Drawer
- ActionBar
- Toolbar
- Collapsing ToolBar
Navigation Component์๋ ๋์ ๋ฐ ์์ ์ ๋ํด ์ง์ ๋ ์ธ์์ ๋ํ ์ ํ ์์ ์ก์ธ์ค๋ฅผ ์ํ ๊ฐ๋จํ ๊ฐ์ฒด ๋ฐ ๋น๋ ํด๋์ค๋ฅผ ์์ฑํ๋ safe args ๋ผ๋ Gradle ํ๋ฌ๊ทธ์ธ์ด ์๋ค.
build.gradle(:project)
dependencies {
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
//...
}
build.gradle(:app)
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'androidx.navigation.safeargs.kotlin'
android {
//...
}
NavGraph์์ argument ์ค์ ํ๊ธฐ
<fragment
android:id="@+id/flow_step_one_dest"
android:name="com.sample.navigation.FlowStepFragment"
tools:layout="@layout/flow_step_one_fragment">
<argument
android:name="flowStepNumber"
app:argType="integer"
android:defaultValue="1"/>
<action...>
</action>
</fragment>/app/build/generated/debug/com/sample/navigation/ ๊ฒฝ๋ก์ Args ์ฝ๋๊ฐ ์์ฑ๋๋ค.

FlowStepFragment ํ๋ฉด์์ ์๋์ ๊ฐ์ด ๋๊ฒจ๋ฐ์ args๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
val safeArgs: FlowStepFragmentArgs by navArgs()FlowStepFragmentํ๋ฉด์ผ๋ก args๋ฅผ ๋๊ธธ ๋๋ ์๋์ ๊ฐ์ด ์ฌ์ฉํ๋ค.
view.findViewById<Button>(R.id.navigate_action_button)?.setOnClickListener {
val flowStepNumberArg = 1
val action = HomeFragmentDirections.nextAction(flowStepNumberArg)
findNavController().navigate(action)
}Navigation Component๋ฅผ ์ฌ์ฉํ์ฌ ๋ฅ ๋งํฌ๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฒ์ ํ ๊ฐ์ง ์ด์ ์ ์ฌ์ฉ์๊ฐ ์ฑ ์์ ฏ, ์๋ฆผ ๋๋ ์น ๋งํฌ์ ๊ฐ์ ๋ค๋ฅธ ์ง์ ์ ์์ ์ ์ ํ ๋ฐฑ ์คํ์ ์ฌ์ฉํ์ฌ ์ฌ๋ฐ๋ฅธ ๋์์์ ์์ํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
DeepLinkAppWidgetProvider.kt
class DeepLinkAppWidgetProvider : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
val remoteViews = RemoteViews(
context.packageName,
R.layout.deep_link_appwidget
)
val args = Bundle()
args.putString("myarg", "From Widget")
val pendingIntent = NavDeepLinkBuilder(context)
.setGraph(R.navigation.mobile_navigation)
.setDestination(R.id.deeplink_dest)
.setArguments(args)
.createPendingIntent()
remoteViews.setOnClickPendingIntent(R.id.deep_link_button, pendingIntent)
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews)
}
}setGraphํ์ ๊ทธ๋ํ๋ฅผ ํฌํจํ๋คsetDestination๋งํฌ๊ฐ ์ด๋๋ก ์ด๋ํ๋์ง ์ง์ ํ๋คsetArguments๋ฅ ๋งํฌ์ ์ ๋ฌํ๋ ค๋ ๋ชจ๋ ์ธ์๋ฅผ ํฌํจํ๋ค
AndroidManifest.xml
<receiver android:name=".DeepLinkAppWidgetProvider">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/deep_link_appwidget_info" />
</receiver>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"
app:startDestination="@+id/home_dest">
...๋ฅ ๋งํฌ๋ฅผ ํตํด ์ง์
ํ๊ฒฝ์ฐ Desination์ผ๋ก app:startDestination ์์ฑ์ ์ฌ์ฉํ์ฌ ๋ฐฑ์คํ์ ํตํด ๋์๊ฐ ํ๋ฉด์ ์ง์ ํ ์ ์๋ค.
๋ฅ ๋งํฌ์ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์ฉ๋ ์ค ํ๋๋ ์น ๋งํฌ๊ฐ ์ฑ์์ ํ๋์ ์ด ์ ์๋๋ก ํ๋ ๊ฒ์ด๋ค.
์ ํต์ ์ผ๋ก ์๋๋ก์ด๋๋ manifestํ์ผ์ <intent-filter>์ ์ฌ์ฉ ํ๊ณ URL์ ์ด๋ ค๋ ํ๋๊ณผ ์ฐ๊ฒฐํ์๋ค.
Navigation Component๋ฅผ ์ฌ์ฉํ๋ฉด ์ด ์์
์ด ๋งค์ฐ ๊ฐ๋จํด์ง๊ณ ํ์ ๊ทธ๋ํ์ ๋์์ URL์ ์ง์ ๋งคํํ ์ ์๋ค.
์ง์ ์ ์ธ URL ์ผ์น ์ธ์๋ ์๋์ ๊ฐ์ ๊ธฐ๋ฅ์ด ์ ๊ณต๋๋ค.
- scheme์ด ์๋ URI๋ http ๋ฐ https๋ก ๊ฐ์ฃผ๋๋ค
- ์๋ฅผ ๋ค์ด,
www.example.com์http://www.example.com,https://www.example.com์ ์ผ์นํ๋ค
- ์๋ฅผ ๋ค์ด,
- ํ์์ ์๋ฆฌ ํ์์๋ฅผ ์ฌ์ฉ {placeholder_name}ํ์ฌ ํ๋ ์ด์์ ๋ฌธ์๋ฅผ ์ผ์น ์ํฌ ์ ์๋ค
- ์๋ฅผ ๋ค์ด,
http://www.example.com/users/4๋http://www.example.com/users/{id}
- ์๋ฅผ ๋ค์ด,
.*์์ผ๋์นด๋๋ฅผ ์ฌ์ฉํ์ฌ 0๊ฐ ์ด์์ ๋ฌธ์๋ฅผ ์ผ์น ์ํฌ ์ ์๋ค- NavController๋ ์๋์ผ๋ก ACTION_VIEW intent๋ฅผ ์ฒ๋ฆฌ ํ๊ณ ์ผ์นํ๋ ๋ฅ ๋งํฌ๋ฅผ ์ฐพ๋๋ค
nav_graph.xml์ ์ด๋ํ ๋์ํ๋ฉด์ ์๋์๊ฐ์ด <deeplink>๋ฅผ ์ถ๊ฐํ๋ค.
<fragment
android:id="@+id/deeplink_dest"
android:name="com.sample.navigation.DeepLinkFragment"
android:label="@string/deeplink"
tools:layout="@layout/deeplink_fragment">
<argument
android:name="myarg"
android:defaultValue="Android!"/>
<deepLink app:uri="www.example.com/{myarg}" />
</fragment>AndroidManifest.xml
<nav-graph>๋ฅผ manifest์ ์ถ๊ฐํด์ค๋ค.
manifest์ ์ ์ธ๋ <nav-graph>๋ Graph์ ์์ฑ๋ ๋ด์ฉ์ ๊ธฐ๋ฐ์ผ๋ก intent-filter, action, category, data ๋ฑ์ ์๋์ผ๋ก ์์ฑํ๋ค.
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<nav-graph android:value="@navigation/nav_graph" />
</activity>์์ฑ๋๋ ๋ด์ฉ์ ์๋์ ๊ฐ๋ค
<activity
android:name="com.example.android.codelabs.navigation.MainActivity">
<intent-filter>
<action
android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.DEFAULT" />
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action
android:name="android.intent.action.VIEW" />
<category
android:name="android.intent.category.DEFAULT" />
<category
android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="http" />
<data
android:scheme="https" />
<data
android:host="www.example.com" />
<data
android:pathPrefix="/" />
</intent-filter>
</activity>