Callback ํจ์๋ ํน์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ ๋ ์คํ๋๋ ํจ์๋ก, ๋ณดํต ๊ณ ์ฐจ ํจ์(higher-order function) ๋ก ์ ๋ฌ๋ฉ๋๋ค. Jetpack Compose์์๋ ์ํ(state) ๊ฐ ๋ณ๊ฒฝ๋์์ ๋ UI๋ฅผ ์ ๋ฐ์ดํธํ๊ธฐ ์ํด ์ฝ๋ฐฑ์ ์์ฃผ ์ฌ์ฉํฉ๋๋ค.
Jetpack Compose์์ ์ปดํฌ์ ๋ธ(Composable) ํจ์๋ ์ํ(state)๋ฅผ ์ง์ ๋ณ๊ฒฝํ์ง ์๊ณ , ์์ ๊ณ์ธต(๋ถ๋ชจ)์์ ์ ๋ฌ๋ฐ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ(Callback)๋ฅผ ํธ์ถํด์ผ ํฉ๋๋ค. ์ด๋ ๋จ๋ฐฉํฅ ๋ฐ์ดํฐ ํ๋ฆ(Unidirectional Data Flow, UDF) ์ ์ ์งํ๊ธฐ ์ํจ์ ๋๋ค.
๋จ๋ฐฉํฅ ๋ฐ์ดํฐ ํ๋ฆ์ด๋, ์ฑ์ ์ํ(State)๊ฐ ์ค์ง ํ ๋ฐฉํฅ์ผ๋ก๋ง ๋ณ๊ฒฝ๋๋๋ก ๊ด๋ฆฌํ๋ ํจํด์
๋๋ค.
์ฆ, ๋ฐ์ดํฐ๋ ์(๋ถ๋ชจ)์์ ์๋(์์)๋ก ํ๋ฅด๊ณ , ์ด๋ฒคํธ๋ ์๋(์์)์์ ์(๋ถ๋ชจ)๋ก ํ๋ฅด๋ ๊ตฌ์กฐ๋ฅผ ์๋ฏธํฉ๋๋ค.
Jetpack Compose๋ ์ํ(state)์ UI๋ฅผ ๋ถ๋ฆฌํ๋ ๊ฒ์ ์์น์ผ๋ก ํฉ๋๋ค. UI ์์๊ฐ ์ง์ ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ฉด ์ ์ง๋ณด์๊ฐ ์ด๋ ต๊ณ , ์์ธก์ด ํ๋ค์ด์ง๋๋ค. Callback์ ์ฌ์ฉํ๋ฉด ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ ๋ ์ํ๋ฅผ ์์ ๊ณ์ธต์์๋ง ๋ณ๊ฒฝํ๋๋ก ๊ฐ์ ํ ์ ์์ต๋๋ค.
๐น ์์: ์๋ชป๋ ๋ฐฉ์ (UI์์ ์ํ ์ง์ ๋ณ๊ฒฝ)
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }
Column {
Text(text = "Count: $count")
Button(onClick = { count++ }) { // UI์์ ์ง์ ์ํ ๋ณ๊ฒฝ โ
Text("Increase")
}
}
}
์ด๋ ๊ฒ ํ๋ฉด UI๊ฐ ์ํ๋ฅผ ์ง์ ๋ณ๊ฒฝํ๊ธฐ ๋๋ฌธ์ ๋จ๋ฐฉํฅ ๋ฐ์ดํฐ ํ๋ฆ์ด ๊นจ์ง๋๋ค.
๐น ์ฌ๋ฐ๋ฅธ ๋ฐฉ์: Callback์ ์ฌ์ฉํ ์ํ ๋ณ๊ฒฝ
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }
Counter(count = count, onIncrement = { count++ }) // Callback ์ฌ์ฉ โญ
}
@Composable
fun Counter(count: Int, onIncrement: () -> Unit) {
Column {
Text(text = "Count: $count")
Button(onClick = onIncrement) { // ์ํ ๋ณ๊ฒฝ์ ๋ถ๋ชจ์๊ฒ ์์
Text("Increase")
}
}
}
โ ์ด๋ ๊ฒ ํ๋ฉด CounterScreen์ด ์ํ๋ฅผ ๊ด๋ฆฌํ๊ณ , Counter ์ปดํฌ์ ๋ธ์ UI ์ญํ ๋ง ๋ด๋นํ๊ธฐ ๋๋ฌธ์ ๋จ๋ฐฉํฅ ๋ฐ์ดํฐ ํ๋ฆ์ ์ ์งํ ์ ์์ต๋๋ค.
Callback์ ์ฌ์ฉํ๋ฉด ์ปดํฌ์ ๋ธ์ ๋ ๋ชจ๋ํํ๊ณ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค. ์ฆ, ์ํ๋ฅผ ์ง์ ๊ด๋ฆฌํ๋ ๊ฒ์ด ์๋๋ผ ์ธ๋ถ์์ ์ ๋ฌ๋ฐ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ํธ์ถํ๊ธฐ๋ง ํ๋ฉด ๋๊ธฐ ๋๋ฌธ์ ๋๋ค.
๐น ์์: ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๋ฒํผ ์ปดํฌ๋ํธ
@Composable
fun CustomButton(label: String, onClick: () -> Unit) {
Button(onClick = onClick) { // ์ด๋ฒคํธ๋ฅผ ์ธ๋ถ์์ ์ ๋ฌ๋ฐ์
Text(text = label)
}
}
@Composable
fun Screen() {
Column {
CustomButton(label = "Click Me", onClick = { println("Button Clicked!") })
CustomButton(label = "Delete", onClick = { println("Item Deleted!") })
}
}
โ CustomButton์ ๋ฒํผ์ ๊ทธ๋ฆฌ๊ธฐ๋ง ํ๊ณ , ์ค์ ๋์์ ํธ์ถํ๋ ๊ณณ์์ ๊ฒฐ์ ํ ์ ์์ด ์ฌ์ฌ์ฉ์ฑ์ด ๋์์ง๋๋ค.
Callback์ ์ฌ์ฉํ๋ฉด ํน์ UI ์์๊ฐ ์คํ๋ ๋ ์ด๋ค ๋์์ด ์ํ๋๋์ง ์ฝ๊ฒ ํ ์คํธํ ์ ์์ต๋๋ค. UI๋ฅผ ํ ์คํธํ ๋, ์ค์ ์ํ ๋ณ๊ฒฝ ์์ด ํจ์ ํธ์ถ ์ฌ๋ถ๋ง ํ์ธํ๋ฉด ๋๊ธฐ ๋๋ฌธ์ ๋๋ค.
๐น ์์: UI ํ ์คํธ
@Test
fun testButtonClick() {
var clicked = false
val onClick = { clicked = true }
composeTestRule.setContent {
CustomButton(label = "Test", onClick = onClick)
}
composeTestRule.onNodeWithText("Test").performClick()
assertTrue(clicked) // Callback์ด ์คํ๋์๋์ง ํ์ธ
}
โ Callback์ ์ฌ์ฉํ๋ฉด UI๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ํ ์คํธํ ์ ์์ผ๋ฉฐ, ์ค์ ์ํ ๋ณ๊ฒฝ ์์ด ์ด๋ฒคํธ ๋์๋ง ๊ฒ์ฆํ ์ ์์ต๋๋ค.
Jetpack Compose๋ ์ํ๊ฐ ๋ณ๊ฒฝ๋ ๋ ์๋์ผ๋ก ๋ฆฌ์ปดํฌ์ง์ (recomposition) ์ ์ํํฉ๋๋ค. ํ์ง๋ง ์ํ๋ฅผ ์ง์ ๋ณ๊ฒฝํ๋ฉด ๋ถํ์ํ UI ๋ฆฌ์ปดํฌ์ง์ ์ด ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ด ํฝ๋๋ค. Callback์ ์ฌ์ฉํ๋ฉด ๋ถ๋ชจ๊ฐ ๋ณ๊ฒฝ๋ ๋ถ๋ถ๋ง ๋ฆฌ์ปดํฌ์ง์ ์ ์ ๋ํ๋ฏ๋ก ์ฑ๋ฅ์ด ์ต์ ํ๋ฉ๋๋ค.
๐น ์์: ์ฑ๋ฅ ์ต์ ํ
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }
Counter(count, onIncrement = { count++ })
}
@Composable
fun Counter(count: Int, onIncrement: () -> Unit) {
Column {
Text("Count: $count") // count๋ง ๋ณ๊ฒฝ๋ ๋ ๋ฆฌ์ปดํฌ์ง์
๋จ
Button(onClick = onIncrement) {
Text("Increase")
}
}
}
โ Counter ์์ฒด๋ ์ํ๋ฅผ ๊ฐ์ง์ง ์์ผ๋ฏ๋ก, ํ์ํ ๋๋ง ๋ฆฌ์ปดํฌ์ง์ ์ด ์ผ์ด๋ ์ฑ๋ฅ์ด ํฅ์๋ฉ๋๋ค.
| ์ฅ์ | ์ค๋ช |
|---|---|
| โ ๋จ๋ฐฉํฅ ๋ฐ์ดํฐ ํ๋ฆ ์ ์ง | UI์์ ์ง์ ์ํ๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ , ๋ถ๋ชจ๊ฐ ์ํ๋ฅผ ๊ด๋ฆฌํ๋๋ก ๊ฐ์ ํจ |
| โ ์ปดํฌ๋ํธ์ ์ฌ์ฌ์ฉ์ฑ ์ฆ๊ฐ | UI์ ๋ก์ง์ ๋ถ๋ฆฌํ์ฌ ๋ค์ํ ๊ณณ์์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅ |
| โ ํ ์คํธ ์ฉ์ด์ฑ | ์ค์ ์ํ ๋ณ๊ฒฝ ์์ด ํจ์ ํธ์ถ ์ฌ๋ถ๋ง ํ์ธ ๊ฐ๋ฅ |
| โ ์ฑ๋ฅ ์ต์ ํ | ๋ถํ์ํ ๋ฆฌ์ปดํฌ์ง์ ์ ๋ฐฉ์งํ๊ณ ํ์ํ ๋ถ๋ถ๋ง ๋ฆฌ๋ ๋๋ง |
Jetpack Compose์์ Callback์ ์ฌ์ฉํ๋ ๊ฒ์ ๋จ์ํ ์ด๋ฒคํธ ์ฒ๋ฆฌ๋ฅผ ๋์ด์, ๊ตฌ์กฐ์ ์ผ๋ก ์ํ ๊ด๋ฆฌ์ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํ ํ์์ ์ธ ํจํด์ ๋๋ค. ํนํ ๋จ๋ฐฉํฅ ๋ฐ์ดํฐ ํ๋ฆ(UDF)์ ์ ์งํ๊ณ , ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๋ฉด์๋ ์ฑ๋ฅ์ด ์ต์ ํ๋ UI๋ฅผ ์ค๊ณํ ์ ์๋๋ก ๋์์ค๋๋ค.