개요
Compose를 사용하다 보면, 어떤 Composable은 일반 함수로, 또 어떤 Composable은 inline 함수로 정의된 것을 확인할 수 있다.
예를 들어 Box 컴포저블도 다음과 같이 두 가지 형태로 제공된다.
@Composable
fun Box(modifier: Modifier) {
Layout(measurePolicy = EmptyBoxMeasurePolicy, modifier = modifier)
}
@Composable
inline fun Box(
modifier: Modifier = Modifier,
contentAlignment: Alignment = Alignment.TopStart,
propagateMinConstraints: Boolean = false,
content: @Composable BoxScope.() -> Unit
) {
val measurePolicy = rememberBoxMeasurePolicy(contentAlignment, propagateMinConstraints)
Layout(
content = { BoxScopeInstance.content() },
measurePolicy = measurePolicy,
modifier = modifier
)
}
이 외에도 Column과Row도 inline 함수이다.
왜 저 Box 컴포저블은 inline 함수일까?
inline을 사용하는 이유는 일반 함수에서와 동일하다. 자주 호출되는 함수거나 복잡한 람다식이 포함된 경우 성능 최적화를 위해 inline을 사용한다.
Box 컴포저블에서도 동일한 이유로 inline 키워드를 적용한다. 특히, 이 함수 내부에서 사용하는 BoxScope는 Box 내부에서만 동작하는 레이아웃 관련 API를 제공하는데, inline 키워드를 사용하면 BoxScope 내부에서 정의된 람다가 매번 객체로 생성되는 것을 방지할 수 있다. 이렇게 하면 함수 호출 비용과 메모리 사용량을 줄여 성능을 더욱 최적화할 수 있다.
💡 즉, 컴포저블에서 inline을 사용하는 이유는 성능 최적화뿐만 아니라, BoxScope와 같은 UI 스코프가 자주 호출되는 상황에서 불필요한 람다 객체 생성을 피하고, 코드가 효율적으로 실행되도록 보장하기 위함이다.
inline을 사용하기 적합한 컴포저블
// inline Comopsable
@Composable
inline fun CustomButton(
modifier: Modifier = Modifier,
shape: RoundedCornerShape = RoundedCornerShape(8.dp),
buttonColors: ButtonColors = ButtonDefaults.buttonColors(),
buttonTitle: String,
enabled: Boolean = true,
crossinline onClick: () -> Unit,
) {
Button(
modifier = modifier.fillMaxWidth(),
onClick = { onClick() },
shape = shape,
colors = buttonColors,
enabled = enabled,
) {
Text(
text = buttonTitle,
fontSize = 14.sp,
fontWeight = FontWeight.W500,
modifier = Modifier.padding(vertical = 15.dp),
)
}
}
// 복잡한 람다
val complexLambda: () -> Unit = {
// 많은 로직이 포함된 경우
for (i in 1..1000) {
println("복잡복잡 $i")
}
}
// Composable 호출
@Composable
fun ExampleUsage() {
CustomButton(
modifier = Modifier.padding(horizontal = 32.dp),
shape = RoundedCornerShape(100.dp),
buttonColors = ButtonDefaults.buttonColors(containerColor = Blue50),
buttonTitle = stringResource(R.string.sign_up_button),
onClick = complexLambda,
)
}
위와 같은 예시에서 inline 키워드는 버튼 클릭 처리에 사용되는 람다 객체 생성을 방지하며, 성능을 최적화할 수 있다.
💡 컴포저블 함수가 자주 호출되거나 복잡한 람다식을 포함할 때 이를 적절히 사용함으로써 성능과 메모리 효율성을 높일 수 있다.
crossinline을 아주 간단하게 알아보면...
crossinline은 inline 함수의 매개변수로 사용되는 람다 표현식에서 사용할 수 있는 키워드이다. 이 키워드를 사용하면 해당 람다에서 return 문을 사용할 수 없게 된다. (비지역 반환(Non-Local Return)이라고도 한다) 이는 inline 함수가 중첩된 함수에서 반환될 때, 호출 스택에 영향을 미쳐 예기치 않은 동작을 방지하기 위한 것이다.
💡 즉, crossinline을 사용하면 해당 람다가 다른 함수의 반환과 상관없이 독립적으로 실행된다.
'Develop > Kotlin' 카테고리의 다른 글
[Android] UI 이벤트 처리 (2) | 2024.10.27 |
---|---|
[Android] 데이터 바인딩 프로퍼티 실종 사건 수사 일지 (37) | 2024.05.12 |
[Kotlin] 얼렁뚱땅 inline 탐험일지 🧐 (0) | 2024.04.06 |
[Kotlin] 확장 함수 (0) | 2024.04.03 |
[Kotlin] Data class (0) | 2024.04.03 |