Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
선언형 UI에서의 상태관리
Search
HyunWoo Lee
December 21, 2024
Programming
640
0
Share
선언형 UI에서의 상태관리
GDG Devfest Songdo 2024에서 진행한 선언형 UI에서의 상태관리의 Speaker Deck입니다.
HyunWoo Lee
December 21, 2024
More Decks by HyunWoo Lee
See All by HyunWoo Lee
Navigating Dependency Injection with Metro
l2hyunwoo
1
320
How Android Uses Data Structures Behind The Scenes
l2hyunwoo
1
750
Understanding Kotlin Multiplatform (Busan)
l2hyunwoo
0
90
Understanding Kotlin Multiplatform
l2hyunwoo
0
350
파급효과: From AI to Android Development
l2hyunwoo
0
350
선언형 UI를 학습할 때 알아둬야하는 키워드들
l2hyunwoo
0
540
Essential concepts to know when learning Declarative UI
l2hyunwoo
2
1.7k
React Native under the hood
l2hyunwoo
0
200
유연한 Composable 설계
l2hyunwoo
0
780
Other Decks in Programming
See All in Programming
SkillsをS3 Filesに置く時のあれこれ
watany
4
1.8k
AlarmKitで明後日起きれるアラームアプリを作る
trickart
0
140
リセットCSSを1行消したらアクセシビリティが向上した話
pvcresin
4
530
横断組織出身のQAEがインプロセスQAEでつまずいたこと・活かせたこと
ty89
0
180
Transactional Change Stream Processing With Debezium and Apache Flink
gunnarmorling
1
120
AIエージェントの隔離技術の徹底比較
kawayu
0
420
Why Laravel apps break—Mastering the fundamentals to keep them maintainable
kentaroutakeda
1
120
inferと仲良くなる10分間
ryokatsuse
1
240
~ 秘伝のタレ化した『神スプシ』と戦う ~ 関数型パラダイムで壊れない仕組みへ
h0r15h0
1
130
Cloudflare で始める Data Platform
ta93abe
0
290
運用エージェントは "作る" から "育てる" へ - 記憶と自己進化の3層設計パターン / self-evolving-agents-three-layer-agent-design
gawa
10
1.2k
タクシーアプリ『GO』の バックエンド開発のおける AI利活用と若者のすべて
pyama86
3
1.6k
Featured
See All Featured
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.5k
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
390
Fireside Chat
paigeccino
42
3.9k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.5k
Amusing Abliteration
ianozsvald
1
180
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
180
Navigating Team Friction
lara
192
16k
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
300
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.4k
The Curious Case for Waylosing
cassininazir
1
360
What's in a price? How to price your products and services
michaelherold
247
13k
Balancing Empowerment & Direction
lara
6
1.1k
Transcript
Incheon ࢶഋ UIীࢲ ࢚కҙܻ - Circuitҗ Rinਸ बਵ۽ അ Android/React
Native Developer, Viva Republica(Toss) Organizer, Kotlin User Groups Seoul/GDG Incheon
࢚కҙܻ ѐ֛җ ࢎ ݾର ҙܻೡ “࢚క” ঌইࠁӝ ࢚క ઑӘ
؊ ੜ ҙܻ ೧ࠁӝ
Speakerdeck Youtube ࢶഋ UI ೨बѐ֛
࢚కҙܻ ѐ֛җ ࢎ
Before Compose class SampleActivity: AppCompatActivity() { private var name =
"" override fun onCreate(bundle: SavedInstanceState?) { super.onCreate(bundle) // ࢲߡాन APIService.getMyName().enqueue(object: Callback { override fun onResponse(ޤदӽ) { name = response.body().name updateUi() // binding.tv.text = name } }) } }
Before Compose • ѐߊо ߸ࣻܳ ߸҃ೞҊ UI ࢚కܳ ߸҃ೞب۾
٘ܳ ࢿ೧ঠೣ • ߸ࣻо ചݶ ߸҃ਸ दఃחؘ ਃبо ڄয • ചݶਸ ߸҃ೞח Ѫ ߸ࣻ ч ইצ ѐߊ
Before Compose - DataBinding class SampleActivity: AppCompatActivity() { private val
viewModel by viewModels() private lateinit var binding: ActivitySampleBinding override fun onCreate(bundle: SavedInstanceState?) { super.onCreate(bundle) binding = DataBindingUtil.setContentView(this, R.layout.ui) binding.viewModel = viewModel } } <layout> <data> <variable name=“vm” type=“com.sample.ViewModel” /> </data> <TextView <!— ࢤۚ —> android:text=“@{vm.user.nam e}” /> </layout>
Data Binding ߸ࣻܳ ߸҃݅ ೧ب ചݶ ࢚కо ߸҃ؽ ߸ࣻо ചݶ
“࢚క”о غب۾ ࢸ҅ ߑೱ ߸҃ , ചݶ ࢚క ߸҃ о ѐߊীࢲ दझమਵ۽ بؽ بੋ ࠽٘ఋ ࢚थҗ ೧ةೞӝ য۰ ী۞ झఖ ۨझ Data Binding -> View Bindingਵ۽ ֈযоח ୶ࣁ Ӓۢীب ࠛҳೞҊ ѐߊо ചݶ ߸ࣻо “࢚క”۽ ੋधೞѱ ػ ࣁ
Compose بੑ റ @Composable fun SampleText() { var text by
remember { mutableStateOf("") } LaunchedEffect(Unit) { text = APIService.getName().await() } TextField(value = text, onValueChange = { text = it }) }
Compose ߸ࣻܳ ߸҃݅ ೧ب ചݶ ࢚కо ߸҃ؽ ୶оੋ ࠽٘ కझ
হ ߸ࣻо ചݶ ࢚కо ؽ
Compose ߸ࣻо ചݶ ࢚క Android Developers - Ui State
࢚క ખ ؊ ࣁ ঌইࠁӝ
࢚కо ޤਃ? UIܳ അೞח ݽٚ ؘఠ
࢚కҙܻо ޤਃ? UIܳ അೞח ݽٚ ؘఠ ܳ ҙܻೞח ߑߨۿ
ࢤпࠁ ҙܻ೧ঠೡ ࢚క ઙܨח নೞ ഥਗоੑ ੑ۱ Form • ܴ/ݫੌ
ࣗ/࠺ߣഐ ١ ੑ۱ UI • ݫੌࣗ ࠂ ৈࠗ • ࠺ߣഐ Ѩૐ • ࠺ߣഐ ഛੋҗ ࠺ߣഐ ੌ ৈࠗ • ডҙ ز
ࢤпࠁ ҙܻ೧ঠೡ ࢚క ઙܨח নೞ
࢚కҙܻ Key Point ؘఠܳ য٣ী, যڌѱ ਤदఃחо?
࢚క৬ ࢚క
࢚క৬ ࢚క ࢚కо ־ҳীѱ ҕਬغҊ חо ೞա ஹನք && ध
ஹನքٜীѱ ҕਬ - ࢚క ஹನքٜ ࢎਊೡ ࣻ ѱ ҕਬ - ࢚క
࢚క(Global State) @Composable fun TodoTheme( darkTheme: Boolean = false,
content: @Composable () -> Unit ) { val colors = todoColors() val typography = TodoTypography() ProvideTodoColorAndTypography(colors, typography){ MaterialTheme(content = content) } }
উ٘۽٘ীࢲ ࢚కҙܻ
উ٘۽٘ীࢲ ࢚కҙܻ
Configuration Change CompositionLocal۽ ׳غח ч ী غפө Config Change۽ ч
ࠛউ೧ݶ ஹನքী ೱ -> জ উࢿ ೞ ۽ࣁझ ࢤݺӝী উਵ۽ ؘఠ द ਊ ޙઁ rememberSavableਸ ഝਊೞݶ 1MB ղ۽ ؘఠܳ ೧ঠೞחؘ ਗೞח ݅ఀ ؘఠܳ ਸ ೞо ࢚ ޅೠ Exception ఠ ࣻ উ٘۽٘ীࢲ ࢚కҙܻ
࢚కҙܻ Android OS: ॄب જؘ, ॄۄ
࢚క ੜ ҙܻೞӝ
ࠗ࠙ ࢚కҙܻ ViewModel ❤
݈ ViewModelী ֍חѱ ୭ࢶ? Configuration Changeী ٮۄࢲ ч ߸҃೧ঠೡ ࣻ
ѓ۟द Fold৬ э ҃ ਵݶ Phone UI, ಟݶ Tablet UI ࠁৈঠೞח ா झ ߊࢤ, ۠ ؘఠܳ Config Change উѱ فݶ য়۰ ী۞ ߊࢤ ܲ ஹನքٜী ࠛਃೠ ࠁܳ ֈѹ п ёח ೞѱ ҙ҅ػ ܲ ёٜী ೧ࢲ ઁೠػ ध݅ਸ оઉঠ ೠ. (Law of Demeter)
None
StateHolder Class @Stable class NiaAppState( val navController: NavHostController, coroutineScope: CoroutineScope,
networkMonitor: NetworkMonitor, userNewsResourceRepository: UserNewsResourceRepository, timeZoneMonitor: TimeZoneMonitor, ) { private val previousDestination = mutableStateOf<NavDestination?>(null) ……
StateHolder Class @Composable fun rememberNiaAppState( … ): NiaAppState { return
remember { NiaAppState( navController = navController, coroutineScope = coroutineScope, networkMonitor = networkMonitor, userNewsResourceRepository = userNewsResourceRepository, timeZoneMonitor = timeZoneMonitor, )
State Holder https://developer.android.com/topic/architecture/ui-layer/ stateholders
Circuit ନݡೞӝ
Circuit? Circuit is a simple, lightweight, and extensible framework for
building Kotlin applications that’s Compose from the ground up.
Circuit? Circuit рױೞҊ о߶ݴ ഛ оמೠ ۨਕ۽, A-Zө Compose݅ਸ ഝਊೞৈ
Kotlin গܻா࣌ਸ ҳ୷ೡ ࣻ णפ.
Circuit? ࢚కҙܻ ߑध݅ਸ ۽ ঠӝ ೞӝ ٸޙী ജ҃ࢸ ١ ҳഅী
ਃೠ ࣁࠗࢎ೦ٜ ઁ৻ೞणפ
Circuit?
Circuit?
Circuit рױೠ ҳઑب
Screen data class CounterScreen(val initialCount: Int): Screen data class DetailScreen(val
id: Long): Screen data class FavoriteScreen: Screen
CircuitUiState, CircuitUiEvent sealed inte rf ace State : CircuitUiState {
data object Loading : State data object NoFavorites : State data class Results( val list: List<Favorite>, val eventSink: (Event) -> Unit ) : State } sealed inte rf ace Event : CircuitUiEvent { data class ClickFavorite(id: Long): Event }
@Composable fun CounterPresenter(): CounterState { var count by rememberSaveable {
mutableStateOf(0) } return CounterState(count) { event -> when (event) { CounterEvent.Increment -> count++ CounterEvent.Decrement -> count-- } } } Presenter
@Composable fun CounterPresenter(): CounterState { var count by rememberRetained {
mutableStateOf(0) } return CounterState(count) { event -> when (event) { CounterEvent.Increment -> count++ CounterEvent.Decrement -> count-- } } } Presenter
rememberRetained
// CircuitUiState ఋੑ expo rt inte rf ace CounterState {
value: number } // CircuitUiState ୡӝ ё const initialState: CounterState = { value: 0, } Redux Toolkitҗ Presenter
// Circuit presenter expo rt const counterSlice = createSlice({ name:
'counter', // Updateغח state initialState, reducers: { // event ࠗ࠙ increment: (state) => { state.value += 1 }, decrement: (state) => { state.value -= 1 } } ) Redux Toolkitҗ Presenter
@CircuitInject(FavoriteScreen::class, ActivityRetainedComponent::class) @Composable fun FavoritesList(state: FavoritesScreen.State) { when (state) {
Loading -> Text(text = stringResource(R.string.loading_favorites)) NoFavorites -> Text( modi fi er = Modi fi er.testTag("no favorites"), text = stringResource(R.string.no_favorites) ) is Results -> { LazyColumn { items(state.list) { Favorite(it, state.eventSink) } } } } } Screen
Circuitী ೠ рۚೠ ࣗх • ഋ জҗ э ҃, ఋੑ/ҳഅী
ೠ ӏઁٜ ࢤೞח ٘ ాੌࢿҗ оةࢿਸ ֫ৈ ࣻ • Unit Testب рױೞѱ ࢿೡ ࣻ • Compose runtimeਸ ഝਊ೧ࢲ ߈ഋ ࢚కܳ ઁೡ ࣻ ח Ѫী
Circuitী ೠ рۚೠ ࣗх • Ѧ ਊೡ ࣻ ח ഥࢎо
ݻա ਸө? • নೠ بҳٜ(Flow, Rx, Legacy View ١)җ interopਸ ೡ ࣻ ݅, ܳ interopೞӝ ਤ೧ ٘ח ݆ࣻ ҕٜࣻਸ ࢤп೧ঠؽ • ъઁ۽ ҳഅ/ࢎਊ೧ঠೞח Ѫٜ(Presenter, Navigator ١) ݆ই पઁ۽ ۽؋࣌ী ਊؼ݅ೠח ޙ
@Composable fun ScreenA() { var isB by rememberRetained { mutableStateOf(true)
} rememberRetained{ "A" } if(isB) { rememberRetained{ "B" } } else { rememberRetained{ "C" } } } takahirom/Rin
উ٘۽٘ীࢲ ࢚కҙܻ ࢚క৬ ࢚క ࢚కܳ ࠁ ؊ ੜ ҙܻೠ ߑߨ
Summary
Thank you Incheon HyunWoo Lee Android(React Native) Developer, Viva Republica(Toss)