Created
November 4, 2021 07:56
-
-
Save sfunke/b9f9cdcd8f02429819ec7d39e1d514bd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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