SelectionContainer { Column { Text("선택 가능한 Text - 1") Text("선택 가능한 Text - 2") DisableSelection { Text("다시 선택 불가능한 Text - 1") Text("다시 선택 불가능한 Text - 2") } Text("선택 가능한 Text - 3") Text("선택 가능한 Text - 4") } } }
각각 맨 끝에 배치하고, 나머지 항목들을 균등하게 가운데에 배치 [Arrangement.SpaceAround] 양 쪽 끝에 동일한 간격으로 패딩을 넣어주고, 가운데에는 양 쪽 끝에 들어간 패딩보다 더 큰 패딩을 사용하여 나머지 아이템들을 균등하게 배치 [Arrangement.SpaceEvenly] 모든 아이템들에 동일한 간격의 패딩을 넣어서 균등하게 배치
override fun Density.arrange( totalSize: Int, // 배치 가능한 전체 높이 sizes: IntArray, // 배치될 아이템들의 높이 배열 outPositions: IntArray, // 아이템들이 배치된 위치가 담길 배열 ) { var y = 0 // 배치할 y 위치 sizes.forEachIndexed { index, size -> outPositions[index] = y // 아이템 배치 y += size // y 에 배치된 아이템 높이 만큼 추가 } if (y < totalSize) { // 만약 배치 가능한 공간이 남았다면 // 전체 높이에서 마지막 아이템의 높이 만큼 뺀 위치에 마지막 아이템을 재배치 outPositions[outPositions.lastIndex] = totalSize - sizes.last() } } }
{ override fun ContentDrawScope.draw() {} } infix fun then(other: Modifier): Modifier = if (other === Modifier) this else CombinedModifier(this, other) fun Modifier.invisible(isInvisible: Boolean) = when (isInvisible) { true -> then(InvisibleModifier) else -> this }
: Any> { // 값을 번들에 저장 가능한 값으로 변환 fun SaverScope.save(value: Original): Saveable? // 번들에 저장된 값을 원래의 값으로 변환 fun restore(value: Saveable): Original? } private val AutoSaver = Saver<Any?, Any>( save = { it }, restore = { it } ) fun <T> autoSaver(): Saver<T, Any> = (AutoSaver as Saver<T, Any>)
using the current SaveableStateRegistry. The default implementation only supports types which can be stored inside the Bundle. Please consider implementing a custom Saver for this class and pass it to rememberSaveable(). data class IntHolder(var value: Int) rememberSaveable { IntHolder(1) }
setContent { var value by remember { mutableStateOf("가") } LaunchedEffect(Unit) { delay(1000) value = "나" } ShowValue(value) } } @Composable fun ShowValue(value: Any) { val valueState by remember { mutableStateOf(value) } Text(valueState.toString()) }
Any) { val valueState by remember(value) { mutableStateOf(value) } Text(valueState.toString()) } @Composable fun ShowValue(value: Any) { val valueState by remember { mutableStateOf(value) }.apply { this.value = value } Text(valueState.toString()) }
구애받지 않고 무작위 병렬로 실행된다. → 하나의 State 에 여러 컴포지션이 동시에 접근할 수 있으며, 교착 상태에 빠질 수 있음 동시성 제어를 위해 MultiVersion Concurrency Control 채택 → ACID 중 I 를 구현하기 위한 방법 중 하나 ACI 를 지키며 구현된 상태 시스템이 Snapshot System
위한 속성 •원자성(Atomicity): 트랜잭션의 결과가 성공/실패 둘 중 하나로 결정돼야 한다. •일관성(Consistency): 트랜잭션을 수행하기 전과 후에 데이터베이스가 일관해야 한다. •고립성(Isolation): 각 트랜잭션은 다른 트랜잭션으로부터 자유로워야 한다. •지속성(Durablility): 트랜잭션의 결과가 영구히 저장돼야 한다. 안드로이드는 데이터를 메모리에 저장하기에 D 를 제외한 ACI 를 컴포즈 스냅샷 시스템에서 지키고 있다.
방법인 동시성 제어(Concurrency Control)중 하나 read, write 작업에 lock 대신 각 트랜잭션이 진행될 때 데이터베이스 스냅샷을 캡쳐하여 해당 스냅샷 안에서 고립된 상태로 트랜잭션을 진행한다. age = 10 [A] age = 20 (커밋 전) [B] age == 10 undo
= 20 (커밋 전) [B] age == 10 StateObject StateRecord undo ACID 의 I 를 구현하는 방법인 동시성 제어(Concurrency Control)중 하나 read, write 작업에 lock 대신 각 트랜잭션이 진행될 때 데이터베이스 스냅샷을 캡쳐하여 해당 스냅샷 안에서 고립된 상태로 트랜잭션을 진행한다.
의 LinkedList 시작점 val firstStateRecord: StateRecord // StateRecord 의 LinkedList 에 새 레코드 추가 fun prependStateRecord(value: StateRecord) // 스냅샷이 충돌했을 때 병합하기 위한 방법 fun mergeRecords( previous: StateRecord, current: StateRecord, applied: StateRecord, ): StateRecord? = null }
StateRecord 가 생성된 스냅샷의 아이디 internal var snapshotId: Int = currentSnapshot().id // 다음 StateRecord internal var next: StateRecord? = null // 다른 StateRecord 에서 값 복사 abstract fun assign(value: StateRecord) // 새로운 StateRecord 생성 abstract fun create(): StateRecord }
이전 StateRecord 값 // b: 새로 만들려고 하는 StateRecord 값 // 새로운 StateRecord 값과 이전 StateRecord 값의 일치 비교 // 값이 다를때만 새로운 StateRecord 를 생성한다. fun equivalent(a: T, b: T): Boolean // previous: 스냅샷을 캡쳐했을 당시의 StateRecord 값 // current: 현재의 StateRecord 값 // applied: 적용하려고 한 StateRecord 값 // 스냅샷이 충돌했을 때 병합하는 방법 fun merge(previous: T, current: T, applied: T): T? = null }