10
11

๋กœ๊ทธ์ธ์ด ๊ตฌํ˜„๋œ fragment์—์„œ ๊ฐ€์ž…๋˜์ง€์•Š์€ ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ ์‹œ๋„๋ฅผ ํ•  ๋•Œ, ์นด์นด์˜ค ๋กœ๊ทธ์ธ์—์„œ ๋ฐ˜ํ™˜ ๋ฐ›์€ access token์„ ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€๋กœ ๋„˜๊ฒจ์•ผํ–ˆ๋Š”๋ฐ, ์ด๋•Œ ์„œ๋กœ ๋‹ค๋ฅธ Fragment๋กœ ์ž‘์„ฑ๋˜์–ด ์žˆ๋Š”๋ฐ๋‹ค viewmodel๋„ ๊ณต์œ ํ•˜๊ณ  ์žˆ์ง€์•Š์•„์„œ ๊ณจ์น˜๊ฐ€ ์•„ํŒ ๋‹ค. datastore๋ฅผ ์ด์šฉํ•ด access token์„ ์ €์žฅํ•˜๋Š” ๊ฑด ๋ฏธ๋ฆฌ ์งœ ๋‘์—ˆ์ง€๋งŒ, ๊ฐ„๋‹จํ•˜๊ฒŒ ํ”„๋ž˜๊ทธ๋จผํŠธ๋ผ๋ฆฌ ๊ฐ’์„ ๋„˜๊ธฐ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์„๊นŒ ๊ณ ๋ฏผํ•˜๋˜ ์ค‘, ํ”„๋กœ์ ํŠธ ํŒ€์žฅํ˜•์ด safe args๋ผ๋Š” ํ‚ค์›Œ๋“œ๋ฅผ ์•Œ๋ ค์ฃผ์…จ๋‹ค.

 

safe args๋Š” android jetpack navigation component์— ์†ํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ ์ค‘ ํ•˜๋‚˜์ด๊ณ , navigation์˜ ํƒ์ƒ‰ ๊ทธ๋ž˜ํ”„ ์†Œ์Šค์ฝ”๋“œ์˜ action์— ๊ฐ’์„ ๋‹ด์•„์„œ ๋„˜๊ธฐ๋Š” ์•„์ฃผ ํš๊ธฐ์ ์ธ ๊ธฐ๋Šฅ์„ ๊ฐ–๊ณ ์žˆ๋‹ค.

๋Œ€์ƒ ์‚ฌ์ด์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ํƒ์ƒ‰ํ•˜๊ณ  ์ „๋‹ฌํ•  ๋•Œ ์œ ํ˜• ์•ˆ์ •์„ฑ์„ ์ œ๊ณตํ•˜๋Š” ๊ทธ๋ž˜ํ”„ ํ”Œ๋Ÿฌ๊ทธ์ธ์ž…๋‹ˆ๋‹ค. ์ธ์ˆ˜๋ฅผ ํ†ตํ•ด ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์€ ์•ˆํ‹ฐํŒจํ„ด์œผ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค. ๊ฐ ๋Œ€์ƒ์€ ํ•ญ๋ชฉ ID์™€ ๊ฐ™์ด ํ•„์š”ํ•œ ์ตœ์†Œ ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ UI ๋ฐ์ดํ„ฐ ๋กœ๋“œ๋ฅผ ๋‹ด๋‹นํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํ”„๋กœ์„ธ์Šค ์žฌ์ƒ์„ฑ์ด ๊ฐ„์†Œํ™”๋˜๊ณ  ์ž ์žฌ์  ๋ฐ์ดํ„ฐ ๋ถˆ์ผ์น˜๊ฐ€ ๋ฐฉ์ง€๋ฉ๋‹ˆ๋‹ค.

๋‚ด ๊ฒฝ์šฐ์—๋Š” string์œผ๋กœ ๋œ ๊ฐ’์„ ๋„˜๊ธฐ๋ฉด ๋˜๋Š” ์ƒํ™ฉ์ด๋ผ ์‚ฌ์šฉํ•˜๊ธฐ ์ ํ•ฉํ•œ ์กฐ๊ฑด์ด๋‹ค. ์ด์ œ ์‚ฌ์šฉ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด์ž

Safe Args ์‚ฌ์šฉ๋ฒ•

gradle ํ”Œ๋Ÿฌ๊ทธ์ธ์ด๋‹ค ๋ณด๋‹ˆ, gradle์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๋ฐฉ๋ฒ•์ด๊ณ , ๊ทธ ๋•Œ๋Š” bundle์„ ์ด์šฉํ•ด ๊ฐ’์„ ๋„˜๊ฒจ์•ผํ•œ๋‹ค.

์ตœ์ƒ์œ„ gradle ํŒŒ์ผ(ํ”„๋กœ์ ํŠธ ์ˆ˜์ค€)์— classpath ์„ค์ •์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

buildscript {
    repositories {
        google()
    }
    dependencies {
        val nav_version = "2.5.3"
        classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version")
    }
}
 

nav_version์€ ๊ณ„์† ์—…๋ฐ์ดํŠธ ๋  ๊ฒƒ์ด๋ฏ€๋กœ version catalog๋‚˜ ๋”ฐ๋กœ buildSrc ๋ชจ๋“ˆ์„ ๋งŒ๋“ค์–ด์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์œ ์ง€ ๋ณด์ˆ˜์— ์ข‹๋‹ค.

์‚ฌ์šฉํ•  app / presentation ๋ชจ๋“ˆ์— ์•„๋ž˜ dependency๋ฅผ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

plugins {
    id("androidx.navigation.safeargs.kotlin")
}
 

AndroidX ํŒจํ‚ค์ง€์ด๊ธฐ ๋•Œ๋ฌธ์— gradle.propertiesํŒŒ์ผ์— android.useAndroidX=true๊ฐ€ ์žˆ์–ด์•ผํ•œ๋‹ค. ์ตœ๊ทผ ์ƒ์„ฑํ•œ ํ”„๋กœ์ ํŠธ๋ผ๋ฉด ์ด๋ฏธ ๋“ค์–ด๊ฐ€ ์žˆ์„ ๊ฒƒ์ด์ง€๋งŒ ์˜ˆ์ „์— ์ƒ์„ฑํ•œ ํ”„๋กœ์ ํŠธ๋ผ๋ฉด ์—†์„ ์ˆ˜๋„ ์žˆ๋‹ค.

 

์ด์ œ ์ฝ”๋“œ๋กœ ๋Œ์•„๊ฐ€๋ฉด, ์†ก์‹ (๋ฐœ์‹ )๋Œ€์ƒ ํ”„๋ž˜๊ทธ๋จผํŠธ์—์„œ ํ”„๋ž˜๊ทธ๋จผํŠธ ์ด๋ฆ„ + Directions๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค. ์ด์ œ ๊ฐ’์„ ๋„˜๊ธธ ์ค€๋น„๋ฅผ ํ•˜๊ฒ ๋‹ค. ๋จผ์ € ๊ฐ’์„ ๋‹ด์•„์„œ ๋„˜๊ธธ action์— ์ธ์ˆ˜๋ฅผ ์„ค์ •ํ•œ๋‹ค.

<action
    android:id="@+id/action_loginFragment_to_signupFragment"
    app:destination="@id/signupFragment">
    <argument
        android:name="acToken"
        app:argType="string"/>
</action>
 

์ด action์€ ๋ฐœ์‹ ๋Œ€์ƒ์—์„œ ์‚ฌ์šฉํ•˜๋Š” action์ด๋‹ค. ์ˆ˜์‹ ๋Œ€์ƒ๋„ argument๋ฅผ ์„ค์ •ํ•ด์ค˜์•ผํ•˜๋Š”๋ฐ, ์ˆ˜์‹ ๋Œ€์ƒ์€ fragment์—์„œ ๊ฐ’์„ ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— argument์˜ ์œ„์น˜๊ฐ€ action์ด ์•„๋‹Œ fragment์ด๋‹ค.

<fragment
    android:id="@+id/signupFragment"
    android:name="com.shypolarbear.presentation.ui.join.JoinFragment"
    android:label="SignupFragment"
    tools:layout="@layout/fragment_signup">
    <argument
        android:name="acToken"
        app:argType="string"/>
</fragment>
 

์ด๊ฒŒ ์ˆ˜์‹ ๋Œ€์ƒ์˜ ์„ค์ •์ด๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํ”„๋ž˜๊ทธ๋จผํŠธ์ด๋ฆ„ + Args์ฝ”๋“œ๊ฐ€ ์ƒ์„ฑ๋˜์–ด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฝ”๋“œ๋กœ ๋Œ์•„๊ฐ€์„œ, action์„ argument๊ฐ’์„ ๋„ฃ์–ด์„œ ์žฌ์ •์˜ํ•œ๋‹ค.

sendTokenToJoin = LoginFragmentDirections.actionLoginFragmentToSignupFragment(token.accessToken)
 

Directions์— ๋ฉ”์„œ๋“œ๋กœ action id๊ฐ€ ์žกํžˆ๊ณ , ์ธ์ˆ˜์— ์‚ฌ์šฉํ•  ๊ฐ’์„ ๋„ฃ์œผ๋ฉด ๋œ๋‹ค. ๋‚ด ์ฝ”๋“œ์—์„œ sendTokenToJoin์€ NavDirection Type์œผ๋กœ, ๋”ฐ๋กœ navigateํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์žˆ๊ธฐ๋•Œ๋ฌธ์— ๊ฑฐ๊ธฐ์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ดlateinit var ์„ ์–ธํ•ด๋’€๋‹ค.

์ˆ˜์‹ ์ชฝ์—์„œ๋Š” ๋” ๊ฐ„๋‹จํ•˜๋‹ค. ktx๊ณ„์—ด dependency๋ฅผ ์‚ฌ์šฉ์ค‘์ด๋ผ๋ฉด(์•„๋งˆ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉ์ค‘์ด๋ผ๋ฉด android-ktx๋ฅผ ์“ฐ๊ณ  ์žˆ์„ ํ™•๋ฅ ์ด ๋†’๋‹ค.) by navArgs()๋ฅผ ์ด์šฉํ•ด ๊ฐ’์„ ๋ฐ›์•„์˜ฌ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

private val args: JoinFragmentArgs by navArgs()
val acToken = args.acToken
 

์ˆ˜์‹ ๋Œ€์ƒ์˜ ์ฝ”๋“œ๋‹ค. ํƒ์ƒ‰ ๊ทธ๋ž˜ํ”„ ui์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ์ง€๋งŒ ๋‚˜๋Š” ์ฝ”๋“œ๋กœ ์ž‘์—…ํ•˜๋Š” ๊ฒŒ ํŽธํ•ด์„œ ์ด๋ ‡๊ฒŒ ์ง„ํ–‰ํ–ˆ๋‹ค.

Safe Args ์‚ฌ์šฉ์ด์ 

๊ณต์‹๋ฌธ์„œ๋ฅผ ๋ณด๋ฉด ์œ ํ˜• ์•ˆ์ „์„ฑ์ด๋ผ๋Š” ๋‹จ์–ด๊ฐ€ ๋‚˜์˜จ๋‹ค. ์ด๊ฒŒ ๋ฒˆ์—ญ์ด ์–ด์ƒ‰ํ•ด์„œ ๊ทธ๋Ÿฐ๊ฑด๋ฐ Type Safety๊ฐ€ ์›๋ฌธ์— ์ ํ˜€์žˆ๋Š” ๋‹จ์–ด๋‹ค.

safe args๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํƒ์ƒ‰ ๊ทธ๋ž˜ํ”„ ์ธ์ž์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํ™•์ธํ•˜๊ธฐ ๋•Œ๋ฌธ ์ปดํŒŒ์ผ ์‹œ์ ์— ์—๋Ÿฌ๋ฅผ ๋ฐœ๊ฒฌ ํ•  ์ˆ˜ ์žˆ์–ด์„œ ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

(10/11 ์ถ”๊ฐ€) Safe Args๋ฅผ ์“ฐ๋ฉด์„œ DataClass๋ฅผ ๋„˜๊ธฐ๋Š” ๋ฒ•

์›์‹œํƒ€์ž…๋งŒ ๋„˜๊ธฐ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ DataClass๋กœ ๋„˜๊ธฐ๊ณ  ์‹ถ๋‹ค๋ฉด Parcelable๋กœ ์„ ์–ธํ•˜๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•˜๋‹ค.

@Parcelize
data class StoreDataArgs(
    val storeId: Int,
    val storeName: String,
    val imageUrl: String
): Parcelable

Parcelable๋กœ ์„ ์–ธํ•ด์ค˜์„œ ์ง๋ ฌํ™”/์—ญ์ง๋ ฌํ™” ๊ณผ์ •์—๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ data class๋ฅผ ์ž‘์„ฑํ•œ๋‹ค์Œ

<action
    android:id="@+id/action_navigation_map_to_navigation_detail"
    app:destination="@id/navigation_detail">
    <argument
        android:name="storeInfo"
        app:argType="com.suchelin.android.util.parcelable.StoreDataArgs"/>
</action>

argType์— data class ์œ„์น˜๋ฅผ ๋„ฃ์œผ๋ฉด ๋œ๋‹ค. ์ˆ˜๋™์œผ๋กœ ํ•˜๋ฉด ํ—ท๊ฐˆ๋ฆด์ˆ˜๋„ ์žˆ์œผ๋‹ˆ ์ด๋•Œ๋Š” ๋„๊ตฌ๋ฅผ ์“ฐ๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค.

Attributes์— add arguments๋ฅผ ๋ˆ„๋ฅด๋ฉด ์ด๋ ‡๊ฒŒ custom parcelable๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๊ณ  IDE๊ฐ€ ์ฐพ์•„์ค€๋‹ค.

์ฐธ์กฐ:

https://developer.android.com/guide/navigation/navigation-pass-data?hl=ko

"๋Œ“๊ธ€, ๊ณต๊ฐ ๋ฒ„ํŠผ ํ•œ ๋ฒˆ์”ฉ ๋ˆ„๋ฅด๊ณ  ๊ฐ€์ฃผ์‹œ๋ฉด ํฐ ํž˜์ด ๋ฉ๋‹ˆ๋‹ค"
๋ฐ˜์‘ํ˜•
COMMENT