First-party tooling ๐ง
Exploring Android KTX
- Android KTX๋ Android ํ๋ ์์ํฌ ๋ฐ Jetpack์ ์ํ ๋ค์ํ ํ์ฅ ์ธํธ์ ๋๋ค.
- ๊ทธ๋ Android KTX ํ์ฅ ์์ฒด๊ฐ Jetpack์ ์ผ๋ถ์ด๋ฉฐ ๊ฐ๋จํ Gradle ์ข ์์ฑ์ผ๋ก ํ๋ก์ ํธ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
- Android KTX์์ ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ ํ์ฅ ๊ธฐ๋ฅ ๋ฐ ๊ณ ์ฐจ ๊ธฐ๋ฅ๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ ํ์ฉํ์ฌ Android API๋ฅผ ๋ณด๋ค Kotlin ๊ด์ฉ์ ์ผ๋ก ๋ง๋๋ ๊ฒ์ ๋ชฉํ๋ก ํฉ๋๋ค.
- ์ข
์์ฑ์ ๋ณด๋ค ๊ฐ๋ณ๊ฒ ๋ง๋ค๊ธฐ ์ํด Android KTX๋ ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ ๋ฐ๋ผ ์ฌ๋ฌ ๊ฐ์ ์์ ์ข
์์ฑ์ผ๋ก ๋๋ฉ๋๋ค. ๊ทธ ์ค ์ผ๋ถ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- Core KTX
- Fragment KTX
- SQLite KTX
- ViewModel KTX
- Navigation KTX
- WorkManager KTX
- Android KTX ์ ์ฒด๋ ๋ง์ ์ ์ฉํ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- ๋ค์ ์น์ ์์๋ Core KTX ๋ฐ Fragment KTX๋ผ๋ ๋ ๊ฐ์ง ํน์ ๋ชจ๋์์ ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Adding Core KTX to your project
๋จผ์ Core KTX๋ฅผ ์ฌ์ฉํ๋๋ก ํ๋ก์ ํธ๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ ค๋ฉด ๋จผ์ google() Maven ์ ์ฅ์๊ฐ ํ๋ก์ ํธ์ ์ถ๊ฐ๋์๋์ง ํ์ธํด์ผ ํฉ๋๋ค. ์ถ๊ฐํ๋ ค๋ฉด ๋ค์ ์ฝ๋๋ฅผ ์ฌ์ฉํ์ธ์.
repositories {
google()
}
๊ทธ ๋ค์ (์ด์ ์ ๋ง๋ค์ด๋ buildSrc ํด๋ ์์ ์ฐธ๊ณ )
object Android {
object Tools {
const val androidGradle = "com.android.tools.build:gradle:3.5.0-beta04"
}
object Ktx {
const val core = "androidx.core:core-ktx:1.0.1"
}
}
์ฑ์์ค build.gradle.kts ์ ์ถ๊ฐ
dependencies {
...
implementation(Deps.Android.Ktx.core)
}
์ด์ Core KTX๊ฐ ํ๋ก์ ํธ์ ์ถ๊ฐ๋์์ผ๋ฏ๋ก ๊ฐ๋ฐ์์ ์ถ์ ๋ ์ฝ๊ฒ ๋ง๋๋ ๋ช ๊ฐ์ง ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Using Core
Core KTX์๋ ๋ค์์ ํฌํจํ์ฌ ๋ค์ํ ํต์ฌ Android ํ๋ ์์ํฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฐ API๋ฅผ ์ค์ฌ์ผ๋ก ๊ตฌ์ถ๋ ํจํค์ง๊ฐ ํฌํจ๋์ด ์์ต๋๋ค.
- androidx.core.animation
- androidx.core.preference
- androidx.core.transition
- androidx.core.view
Android KTX๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ซํผ API๋ฅผ ๋จ์ํํ๋ ๊ฐ์ฅ ์ข์ ์ ์ค ํ๋๋ SharedPreferences๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. Kotlin์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์ผ๋ฏ๋ก ๋ช ์์ ์ผ๋ก commit() ๋๋ apply()๋ฅผ ํธ์ถํ ํ์๊ฐ ์๋ ๋งค์ฐ ์ ์ฐฝํ ๊ตฌ๋ฌธ์ SharedPreferences ํธ์ง์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
val preferences = getPreferences(Context.MODE_PRIVATE)
preferences.edit {
putBoolean("key", false)
putString("key2", "value")
}
Android KTX์์ ์ ๊ณตํ๋ ์ ์ฉํ ๊ธฐ๋ฅ์ ๋ ๋ค๋ฅธ ์๋ View.onPreDraw() ํ์ฅ ๊ธฐ๋ฅ์ ๋๋ค.
button.doOnPreDraw {
// Perform an action when view is about to be drawn
}
์ด๋ฅผ ํตํด ์ ๋ฆฌ์ค๋๋ฅผ ๋ง๋ค๊ฑฐ๋ ํด๋น ๋ฆฌ์ค๋๋ฅผ ๋ฑ๋ก ์ทจ์ํ์ง ์๊ณ ๋ View๊ฐ ๊ทธ๋ ค์ง๋ ค๊ณ ํ ๋ ์คํ๋ ๋ก์ง์ด ํฌํจ๋ ๋๋ค๋ฅผ ์ ์ํ ์ ์์ต๋๋ค.
Using Fragment KTX
์ด์ ํ๋๊ทธ๋จผํธ ์์ ์ ์ํ ์ ํธ๋ฆฌํฐ ๊ธฐ๋ฅ์ด ํฌํจ๋ Fragment KTX ๋ชจ๋์ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ๋จผ์ ์๋ก์ด ์ข ์์ฑ ์์๋ฅผ ์ ์ํฉ๋๋ค.
object Android {
...
object Ktx {
const val core = "androidx.core:core-ktx:1.0.1"
const val fragment = "androidx.fragment:fragment-ktx:1.0.0"
}
}
์ด์ app/build.gradle.kts๋ฅผ ์ ๋ฐ์ดํธํ๊ฒ ์ต๋๋ค.
dependencies {
...
implementation(Deps.Android.Ktx.core)
implementation(Deps.Android.Ktx.fragment)
}
์ข ์์ฑ์ด ์ถ๊ฐ๋๋ฉด ๋ค์๊ณผ ๊ฐ์ด commit() ํ์ฅ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ FragmentTransactions๋ฅผ ์ ์ํ ์ ์์ต๋๋ค.
supportFragmentManager.commit {
addToBackStack("fragment name")
add(SampleFragment(), "tag")
setCustomAnimations(R.anim.abc_fade_in, R.anim.abc_fade_out)
}
์ด๋ ๊ฒ ํ๋ฉด ์๋ก์ด FragmentTransaction์ ์ถ๊ฐํ ๋ Kotlin์ด ๋ ๊ด์ฉ์ ์ผ๋ก ๋๊ปด์ง๊ณ ์ด๋ฌํ ์์ ๊ณผ ๊ด๋ จ๋ ์ผ๋ถ ์์ฉ๊ตฌ๊ฐ ์ ๊ฑฐ๋ฉ๋๋ค.
Core KTX ๋ฐ Fragment KTX์์ ๋ณด์๋ฏ์ด ์ด๋ฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ Android ๊ฐ๋ฐ ๊ฒฝํ์ ์ค์ ๋ก ํฅ์์ํฌ ์ ์์ต๋๋ค. ์ด๋ฌํ ์ ํ์ ํ์ฅ ๋ฐ ์ถ๊ฐ ๊ธฐ๋ฅ์ Android KTX ์ข ์์ฑ ์ ์ฒด์์ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ Android ๊ฐ๋ฐ์ ์ํด Kotlin์ ํ์ฉํ๋ ๋ฐ ์ค์ ๋ก ๋์์ด ๋ ์ ์์ต๋๋ค.
๋ค์ ์น์ ์์๋ Kotlin Android Extensions ํ๋ฌ๊ทธ์ธ๊ณผ ์ด ํ๋ฌ๊ทธ์ธ์ด Kotlin์ ์ฌ์ฉํ์ฌ Android ๊ฐ๋ฐ์ ๋ ์ฝ๊ฒ ๋ง๋๋ ์ถ๊ฐ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Using Kotlin Android Extensions
Kotlin Android Extensions ํ๋ฌ๊ทธ์ธ์ Kotlin ๋ฐ Android ์์ ์ ์ํ ์ถ๊ฐ ๊ธฐ๋ฅ ์ธํธ๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด์ ๋ํ ๊ฐ์ฅ ํฐ ๋ ๊ฐ์ง ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- findViewById() ์์ด Android ๋ณด๊ธฐ ์ฐธ์กฐ
- Parcelable ๊ตฌํ ์์ฑ
์ด๋ฌํ ๊ธฐ๋ฅ์ ์ฌ์ฉ ์ค์ ํ๋ ค๋ฉด app/build.gradle.kts ํ์ผ์ androidExtensions ๋ธ๋ก ๋ด์์ ์คํ ๊ธฐ๋ฅ์ ์ฌ์ฉ ์ค์ ํด์ผ ํฉ๋๋ค. ๋ค์ ์ฝ๋ ์ค๋ํซ์ ์ด ์์ ์ ์ํํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค.
androidExtensions {
isExperimental = true
}
์ด ๊ตฌ์ฑ์ด build.gradle.kts ํ์ผ์ ์ถ๊ฐ๋๋ฉด Android Extensions ํ๋ฌ๊ทธ์ธ์ ํฌํจ๋ ๊ธฐ๋ฅ์ด ํ์ฑํ๋ฉ๋๋ค. ๋ค์ ์น์ ์์๋ Android view๋ฅผ ๊ตฌ์ถํ๋ ๋ฐ ๋์์ด ๋๋ ์ด๋ฌํ ๊ธฐ๋ฅ ์ค ํ๋๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Binding views with Kotlin Android Extensions
์คํ ๊ธฐ๋ฅ์ด ์ผ์ง๋ฉด ํฉ์ฑ ๋ทฐ ๋ฐ์ธ๋ฉ์ ์ฐธ์กฐํ์ฌ ๋ทฐ์ ์ก์ธ์คํ ์ ์์ต๋๋ค. ์ด๊ฒ์ Android Extensions ํ๋ฌ๊ทธ์ธ์ด ์ฐ๋ฆฌ๋ฅผ ์ํด ๋ทฐ ๋ฐ์ธ๋ฉ์ ์์ฑํ๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. MainActivity์์ ๋ค์ ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ์ถ๊ฐํ์ฌ activity_main.xml ํ์ผ์ ์ ์๋ ๋ฒํผ์ ์ฐธ์กฐํ ์ ์์ต๋๋ค.
import kotlinx.android.synthetic.main.activity_main.button
๊ฐ์ ธ์ค๊ธฐ๋ฅผ ํฌํจํ๊ณ ๋๋ฉด findViewById() ๋๋ ๋ค๋ฅธ ๋ณ์ ์ ์ธ์ ํธ์ถํ์ง ์๊ณ ๋ ํด๋น ๋ทฐ๋ฅผ ์ง์ ์ฐธ์กฐํ ์ ์์ต๋๋ค.
button.apply {
text = "Hello Kotlin"
gravity = Gravity.START
setTextColor(resources.getColor(R.color.colorAccent))
}
๊ธฐ๋ณธ์ ์ผ๋ก ๋ณด๊ธฐ ์ด๋ฆ์ XML์ android:id ์์ฑ์ ๋ฐ๋ผ ์ง์ ๋ฉ๋๋ค. ์ด ๊ฒฝ์ฐ ๋ฒํผ์ ID๊ฐ '@+id/button'์ด๋ฏ๋ก ์์ฑ๋ ๋ฐ์ธ๋ฉ์ ์ด๋ฆ์ ๋ฒํผ์ผ๋ก ์ง์ ๋์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ค๋ฅธ ๋ณ์ ์ด๋ฆ์ ์ฌ์ฉํ๊ฑฐ๋ ๋ค๋ฅธ ์ด๋ฆ๊ณผ ์ถฉ๋์ด ์๋ ๊ฒฝ์ฐ ๋ค์ ๊ตฌ๋ฌธ์ ์ฌ์ฉํ์ฌ import ๋ฌธ์ ์ ๋ฐ์ดํธํ๊ณ ๋์ฒด ์ด๋ฆ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
import kotlinx.android.synthetic.main.activity_main.button as theButton
๊ฐ์ ธ์ค๊ธฐ๋ฅผ ์ ๋ฐ์ดํธํ ํ ์ด์ Button์ด๋ผ๋ ์ด๋ฆ์ผ๋ก ๋ฒํผ์ ์ฐธ์กฐํ ์ ์์ต๋๋ค.
theButton.apply {
text = "Hello Kotlin"
gravity = Gravity.START
setTextColor(resources.getColor(R.color.colorAccent))
}
ํฉ์ฑ ๋ทฐ ๋ฐ์ธ๋ฉ์ ์กํฐ๋นํฐ ๋ฐ ํ๋๊ทธ๋จผํธ์ ํจ๊ป ์ฌ์ฉํ ๋ ์บ์ฑ์ ์ฒ๋ฆฌํ๊ณ ์ฌ์ฉ์ ์ง์ ๋ทฐ์์๋ ์๋ํ๋๋ก ๋ง๋ค ์ ์์ต๋๋ค. Gradle ํ์ผ์์ androidExtensions ๋ธ๋ก์ ์ ๋ฐ์ดํธํ์ฌ ์๊ตฌ ์ฌํญ์ ๋ฐ๋ผ ์บ์ฑ ์ ๋ต์ ์ ์ดํ ์๋ ์์ต๋๋ค.
androidExtensions {
// HASH_MAP, SPARSE_ARRAY, NONE
defaultCacheImplementation = "HASH_MAP"
}
๋ณด๊ธฐ ์ฐธ์กฐ์ Kotlin Android Extensions๋ฅผ ์ฌ์ฉํ๋ฉด Butterknife ๋๋ ์ฌ๋ฌ findViewById() ํธ์ถ๊ณผ ๊ฐ์ ํ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํผํ ์ ์์ต๋๋ค. ์ด๋ฌํ ํฉ์ฑ ๋ฐ์ธ๋ฉ(DataBinding, ViewBinding ๋๋ findViewById())์ ์ฌ์ฉํด์ผ ํ๋์ง ์ฌ๋ถ๋ ํ๋ก์ ํธ์ ๊ธฐ๋ณธ ์ค์ ์ ๋ฐ๋ผ ํฌ๊ฒ ๋ฌ๋ผ์ง๋ฉฐ ํ๋ก์ ํธ๋ณ๋ก ํ๊ฐํด์ผ ํฉ๋๋ค.
Generating Parcelable implementations
Parcelable์ ๋ณด๋ค ์ฑ๋ฅ์ด ๋ฐ์ด๋ ์ง๋ ฌํ API ์ ๊ณต์ ๋ชฉํ๋ก ํ๋ Android ๊ฐ๋ฐ์ ๊ณตํต ์ธํฐํ์ด์ค์ ๋๋ค. Parcelable ์ธํฐํ์ด์ค์ ๊ตฌํ์ ์์ฑํ๋ ๊ฒ์ ๋จ์ํ๊ณ ๋ฐ๋ณต์ ์ธ ๋ง์ ์ฝ๋๋ฅผ ์์ฑํ๋ ์ง๋ฃจํ๊ณ ์์ฉ๊ตฌ๋ก ๊ฐ๋ ์ฐฌ ์์ ์ด ๋ ์ ์์ต๋๋ค. ๊ณ ๋ง๊ฒ๋ Kotlin Android Extensions๋ Parcelable ๊ตฌํ์ ์์ฑํ ์ ์๋ ์ฃผ์์ ์ ๊ณตํฉ๋๋ค. ์ด ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ค๋ฉด Parcelable์ ๊ตฌํํ๋ ๋ชจ๋ ํด๋์ค์ @Parcelize ์ฃผ์์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
@Parcelize
data class Person(val firstName: String, val lastName: String): Parcelable
@Parcelize ์ฃผ์์ ๋ชจ๋ธ ๊ฐ์ฒด์ ์ถ๊ฐํ๋ฉด ํ๋ฌ๊ทธ์ธ์ด ํ์ํ Parcelable ๊ตฌํ์ ์์ฑํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํด๋น Parcelable ๊ตฌํ์ ๊ตฌํ ๋ฐ ์ ์ง ๊ด๋ฆฌ๋ฅผ ๊ฑด๋๋ธ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํด๋์ค์ ํ์ํ ์ฝ๋์ ์์ด ์ค์ด๋ค๊ณ ํด๋์ค๊ฐ ์์ ๋ ๋๋ง๋ค Parcelable ๊ตฌํ์ ์ ๋ฐ์ดํธํ ํ์๊ฐ ์์ต๋๋ค. ํ๋ฌ๊ทธ์ธ์ ์ฝ๋๊ฐ ์ปดํ์ผ๋ ๋ ์ด๋ฅผ ์ํํฉ๋๋ค. ํ๋ฌ๊ทธ์ธ์ ์ฝ๋๊ฐ ์ปดํ์ผ๋ ๋ ์ด๋ฅผ ์ํํฉ๋๋ค. ์ด๋ ์์ฑ ์์ ์์ ์ผ๋ฐ์ ์ผ๋ก ๋ฐ์ํ ์ ์๋ ์ค๋ฅ๋ก๋ถํฐ ๋ณดํธํ๋ ๋ฐ ๋์์ด ๋์ง๋ง Parcelable ๊ตฌํ์ ์ ๋ฐ์ดํธํ๋ ๊ฒ์ ์์ด๋ฒ๋ฆฝ๋๋ค.
Kotlin Android Extensions ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํ๋ฉด ์์ฑ ๋ฐ ์ ์ง ๊ด๋ฆฌํด์ผ ํ๋ ์ฝ๋์ ์์ ์ค์ด๊ณ ํ๋ฌ๊ทธ์ธ์ด ์ผ๋ฐ์ ์ธ ์์ฉ๊ตฌ ์ฝ๋๋ฅผ ์์ฑํ๋๋ก ํ ์ ์์ต๋๋ค.
Summary
์ด ์ฅ์์๋ Kotlin๊ณผ Android ๊ฐ๋ฐ ๊ฐ์ ๊ด๊ณ๋ฅผ ์ดํด๋ณด์์ต๋๋ค. ์ฐ๋ฆฌ๋ ์ด์ฐฝ๊ธฐ๋ถํฐ ์ต๊ทผ Google์ Kotlin First ๋ฐํ๊น์ง Kotlin์ด Android์ ์ฑํ๋ ์ญ์ฌ๋ฅผ ์ดํด๋ณด์์ต๋๋ค. Kotlin์ ์ง์ํ์ฌ ์ฒ์๋ถํฐ ์๋ก์ด Android ํ๋ก์ ํธ๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ๊ณผ Kotlin ๊ด์ฉ์ Android ์ฝ๋๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ์์ธํ ์ค๋ช ํ์ต๋๋ค. ๋ง์ง๋ง์ผ๋ก Android-KTX, Kotlin Android Extensions ๋ฐ Android ์ํคํ ์ฒ ๊ตฌ์ฑ ์์์ ๊ฐ์ ๋ช ๊ฐ์ง ํน์ Kotlin ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฐ ๋๊ตฌ๋ฅผ ์กฐ์ฌํ์ต๋๋ค. ์ฐ๋ฆฌ๋ ์ด๋ฌํ ๋๊ตฌ๊ฐ Kotlin์ ํ์ฉํ์ฌ Android ๊ฐ๋ฐ์ ๋ ์ฝ๊ณ ์ฆ๊ฒ๊ฒ ๋ง๋๋ ๋ฐฉ๋ฒ์ ๋ณด์์ต๋๋ค.
๋ค์ ์ฅ์์๋ ์น ๊ฐ๋ฐ์ ์ํด Android ์ธ๋ถ์์ Kotlin์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Referencs
mastering kotlin
2022.01.01 - [Android/Kotlin] - [์ฝํ๋ฆฐ] ๋ ์ข์ Companion object ์ฌ์ฉ ๋ฐฉ๋ฒ