현재 안드로이드 스튜디오 최신 버전에서는 Strong Skipping Mode 가 기본적으로 활성화 되어 있으나, 기존에는 이러한 기능이 없었다.
또한 Strong Skipping Mode 가 기본적으로 활성화 되어 있다고 하더라도 이 기능이 정확히 어떤 것인지 알 수 있도록 공유하는 것이 좋을 것이라 생각되어 글을 쓰게 되었다.
restartable인 경우 Unstable 한 객체임에도Compose Compiler 가 해당 객체를 Skippable로 간주, Compose Runtime 은 이를 우선동일성 체크 후 동등성 체크를 거치게 된다.
이 Strong Skipping Mode 를 사용하기에 앞서 Stable 과 Unstable 에 간단하게 알아야한다.
Stable 의 경우 Compose 가 안정적인 객체로 판단하여 Skippable 하게 설정하는데, 리컴포지션 과정에서 equals 체크를 진행하며 이전과 같다고 판단되면 Skip 할 수 있게 된다.
Unstable 의 경우 Compose 가 안정적이지 못한 객체로 판단하여 값이 변하지 않더라도 Instance 가 다르다면, Skipping 을 하지 못하여 Recomposition 이 발생한다.
Stable 의 경우 Primitive Type 이거나, @Stable Marker 를 사용하여 만들어졌거나, class 내부의 프로퍼티가 모두 Stable 이어야 한다.
List 와 같은 interface 는 구현에 의해 내부가 변할 수 있으므로 Unstable 이다.
Lambda 의 경우 값을 캡처하지 않거나 안정적인 객체를 캡처하면 Stable 이지만, Unstable 객체를 캡처하는 경우 불안정하게 작동된다.
class MainActivity() : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
Scaffold {
Column(Modifier
.fillMaxSize()
.padding(it)
) {
Parent()
}
}
}
}
}
@Composable
fun Parent(){
var count by remember { mutableStateOf(1) }
val list = remember { listOf(1, 2, 3) }
Child(list)
Child2(count)
Button({ count++ }) { }
}
@Composable
fun Child(list: List<Int>){
Text(text = list.toString())
}
@Composable
fun Child2(count: Int){
Text(text = count.toString())
}
위 코드에서 Child 의 경우 Unstable 인 List<Int> 를 파라미터로 받고 있다. 이러한 이유로 Button 을 클릭하여 Parent 를 리컴포지션 시키면 Strong Skipping Mode 에 따라 Recomposition 에 차이가 발생한다.
Strong Skipping Mode 가 꺼져있을 때를 확인해보자.


앱을 실행하여 버튼을 3번 누르게 되는 경우, List 가 바뀌지 않았음에도 Unstable 하여 Child 에 리컴포지션이 발생하게 된다.


List 는 Unstable 하지만 Strong Skipping Mode 에 의해 Skippable 하게 되었고, 동등성 비교에서 true 되어 Skip 되었다.
Child.Text 의 경우 Child 가 Recomposition 되지 않았으니 아무런 동작하지 않는다.
@Composable
fun Parent(){
val list = remember { mutableListOf(1, 2, 3) }
var count by remember { mutableStateOf(0) }
Child { Timber.d(list.toString()) }
Button({ count++ }) { Text(text = "카운트 증가") }
Text(text = count.toString())
}
@Composable
fun Child(lambda: () -> Unit){
Button(lambda) { Text(text = "람다") }
}


Lambda 내부에서 unstable 객체를 캡처하였지만, Strong Skipping Mode 에 의해 Skippable 하게 되었고 $composer.changedInstance(list) 가 true 이기에 스킵 되었다.