androidkotlinandroid-jetpack-composecompose-recomposition

Why is ViewModel method reference not stable (causing recomposition) but lambda is? (Jetpack Compose)


I have an MVI architecture with and activity containing the main screen

class MainActivity : ComponentActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      MyTheme {
        val viewModel: MainScreenViewModel = viewModel(factory = MainScreenViewModel.Factory)
        val state by viewModel.viewState.collectAsState()
        MainScreen(state, viewModel::handleEvent)
      }
    }
  }
}

The main screen looks somewhat like this:

@Composable
fun MainScreen(state: MainScreenState, onEvent: (Event) -> Unit) {
  TaskList(
    tasks = state.items,
    onEvent = onEvent,
  )
}

@Composable
fun TaskList(tasks: List<TaskState>, onEvent: (Event) -> Unit) {
  LazyColumn {
    items(items = tasks, key = { it.id }) {
      Task(state = it, onEvent = onEvent)
    }
  }
}

Now, if the ViewModel emits a new MainScreenState where one TaskState is changed, the TaskList recomposes. This is expected, as a new list object is passed. But not only the changed Task is recomposed, but every Task composable in the list. The reason for this is not the TaskState, it is stable.

What seems to cause the recomposition is the onEvent callback. If I change onEvent = onEvent to onEvent = { onEvent(it) } in the MainScreen, the problem is solved. But I do not understand why. Shouldn't method references be stable as-well? I have even checked the hashCode, it's always the same.


Solution

  • You need to look at the number of recompositions in release mode, not debug mode.

    I don't know why, but thanks to this article https://itnext.io/exercises-in-futility-jetpack-compose-recomposition-6ea3cf9bc1b4

    and https://github.com/theapache64/rebugger

    I found that in release lambda was stable.

    The problem is the combiler in debug mode