Skip to content

Instantly share code, notes, and snippets.

@sfunke
Created November 4, 2021 07:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sfunke/b9f9cdcd8f02429819ec7d39e1d514bd to your computer and use it in GitHub Desktop.
Save sfunke/b9f9cdcd8f02429819ec7d39e1d514bd to your computer and use it in GitHub Desktop.
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import androidx.compose.foundation.lazy.items
import androidx.compose.ui.window.WindowState
import androidx.compose.ui.window.singleWindowApplication
fun main() = singleWindowApplication(
title = "Recomposition Demo",
state = WindowState(width = 400.dp, height = 800.dp)
) {
RecomposeDemo()
}
// data models
@Immutable
data class Items(
val items: List<String>
)
typealias Error = Throwable
// View Model
class RecomposeDemoViewModel(
var viewModelScope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate),
val repo: DummyRepo = DummyRepo()
) {
data class UiState(
val items: Items = Items(emptyList()),
val isLoading: Boolean = false,
val error: Error? = null
)
var uiState by mutableStateOf(
UiState(items = Items(repo.sampleData))
)
fun changeSomeUiState() {
uiState = uiState.copy(isLoading = !uiState.isLoading)
}
fun refresh() {
viewModelScope.launch {
uiState = uiState.copy(isLoading = true)
val items = repo.getData()
uiState = uiState.copy(isLoading = false, items = items)
}
}
}
// root view
@Composable
fun RecomposeDemo() {
val viewModel by remember { mutableStateOf(RecomposeDemoViewModel()) }
LogCompositions("Root")
Column {
Text("This demo uses a monolithic state data class.")
val uiState = viewModel.uiState
// Header
Row {
if (uiState.isLoading) {
CircularProgressIndicator()
}
Button(onClick = viewModel::changeSomeUiState) {
Text(text = "Toggle some UI State")
}
Button(onClick = viewModel::refresh) {
Text(text = "Refresh Items")
}
}
// Why do list items in this LazyColumn recompose??
MyColumn(items = viewModel.uiState.items)
}
}
// Lazy Column
@Composable
fun MyColumn(
items: Items,
modifier: Modifier = Modifier
) {
LogCompositions("\tMy LazyColumn")
LazyColumn(
modifier = modifier.fillMaxWidth()
) {
items(items.items) { item ->
LogCompositions("\t\t${item}")
Text(item, modifier = Modifier.padding(horizontal = 16.dp, vertical = 36.dp))
Divider()
}
}
}
// LogComposition taken from here:
// https://www.jetpackcompose.app/articles/donut-hole-skipping-in-jetpack-compose
class Ref(var value: Int)
// Note the inline function below which ensures that this function is essentially
// copied at the call site to ensure that its logging only recompositions from the
// original call site.
@Composable
inline fun LogCompositions(tag: String, msg: String = "") {
val ref = remember { Ref(0) }
SideEffect { ref.value++ }
println("${tag} >> Compositions: $msg ${ref.value}")// @${Thread.currentThread().name}")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment