๐ ์ฝํ๋ฆฐ ํ๋ก
ํ๋ก๋?
- ๋น๋๊ธฐ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์ฒ๋ฆฌํ๊ธฐ ์ํ ๋๊ตฌ
- ์๊ฐ์ ๋ฐ๋ผ ์ฌ๋ฌ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌ ๊ฐ๋ฅ
- LiveData์ฒ๋ผ UI์ ์ฐ๋๋ ๊ฐ๋ฅํ๋ฉด์๋ ๋ ๋ค์ํ ๊ธฐ๋ฅ๊ณผ ์ฐ์ฐ ์ ๊ณต
- ๊ธฐ๋ณธ์ ์ผ๋ก ์ฝ๋ ์คํธ๋ฆผ=> ๊ตฌ๋
ํ๊ธฐ ์ ๊น์ง๋ ์๋ฌด ์์
๋ x
ViewModel์ Flow ์ ์ธํ๊ธฐ
- ViewModel์์ Flow๋ฅผ ์ ์ธํ ๋๋ ๋ณดํต flow {} ๋ธ๋ก ์ฌ์ฉ
- ๋ธ๋ก ์์์๋ emit() ํจ์๋ฅผ ์ด์ฉํด ๋ฐ์ดํฐ๋ฅผ ํ๋์ฉ ๋ฐฉ์ถ
val numberFlow = flow {
for (i in 1..5) {
emit(i)
delay(1000)
}
}
-> ๋ฐ์ดํฐ๋ฅผ ํ๋์ฉ, ์ผ์ ํ ๊ฐ๊ฒฉ์ผ๋ก ๋ด๋ณด๋ด๋ ๊ตฌ์กฐ ๊ฐ๋ฅ
-> ๋น๋๊ธฐ ๋ฃจํ์ฒ๋ผ ์๋
Compose์์ Flow ์์งํ๊ธฐ
- Flow๋ฅผ ์ํ๋ก ๋ฐ๊ฟ UI์ ์ฐ๊ฒฐํด์ฃผ๋ collectAsState()๋ฅผ ์ฌ์ฉ
- Flow์์ ๋์ค๋ ๊ฐ์ ์ค์๊ฐ์ผ๋ก ๋ฐ์ ์ํ๋ก ์ ์ฅํ๊ณ , ์ด ์ํ๊ฐ ๋ฐ๋๋ฉด ์๋์ผ๋ก UI๋ฅผ ๋ค์ ๊ทธ๋ ค์ค
=> ๋น๋๊ธฐ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ฒ UI์ ์ฐ๊ฒฐํ ์ ์๊ฒ ํด์ฃผ๋ ๋๊ตฌ
val number by viewModel.numberFlow.collectAsState(initial = 0)
Flow ์ค๊ฐ ์ฐ์ฐ์ ์ฌ์ฉํ๊ธฐ
- Flow๋ ๋จ์ํ ๋ฐ์ดํฐ ํ๋ฆ๋ง ์ ๊ณตํ๋ ๊ฒ์ด ์๋๋ผ, ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํ๊ณ ์ ์ดํ๋ ๋ค์ํ ์ค๊ฐ ์ฐ์ฐ์ ์ ๊ณต
ex) map์ ๋ฐ์ดํฐ๋ฅผ ๋ณํํ๊ณ , filter๋ ์กฐ๊ฑด์ ๋ง๋ ๋ฐ์ดํฐ๋ง ํต๊ณผ
val newFlow = numberFlow
.filter { it % 2 == 0 }
.map { it * 10 }
=> Flow๋ ์ฒด์ด๋ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ ํ๋ฆ์ ๊ตฌ์ฑ ๊ฐ๋ฅ
=> ๋ณต์กํ ๋ก์ง๋ ๊ฐ๊ฒฐํ๊ฒ ํํ ๊ฐ๋ฅ
๋ฒํผ ์ฌ์ฉํ๊ธฐ
- buffer()๋ฅผ ์ฌ์ฉํด์ ์์ฐ์๊ฐ ๋น ๋ฅด๋๋ผ๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ ์ ์ฅํด๋๊ณ , ์๋น์๊ฐ ๋ฐ๋ผ์ก์ ์ ์๊ฒ ํจ
numberFlow
.buffer()
.collect { ... }
=> ์ค์ ์ฑ์์ ๋คํธ์ํฌ ์๋, ์ฌ์ฉ์ ์
๋ ฅ ์๋ ์ฐจ์ด ๋ฑ์ ์ฒ๋ฆฌํ ๋ ์ ์ฉ
์ข
๋จ ์ฐ์ฐ์
- Flow๋ ๋ง์ง๋ง์ ๋ฐ๋์ ์ข
๋จ ์ฐ์ฐ์๊ฐ ์์ด์ผ ์คํ
- ๋ํ์ ์ธ ๊ฒ: collect()
=> flow๋ก ์ ์๋ง ํด๋๊ณ collect()๋ฅผ ํ์ง ์์ผ๋ฉด ์๋ฌด ์ผ๋x
numberFlow.collect { value ->
Log.d("TAG", "๊ฐ: $value")
}
- first(), toList() ๊ฐ์ ๋ค์ํ ์ข
๋จ ์ฐ์ฐ์๊ฐ ์์ผ๋ฉฐ, ์ํฉ์ ๋ฐ๋ผ ์ ์ ํ๊ฒ ์ฌ์ฉ
Flow ํํํ
-
์ด์ค ๊ตฌ์กฐ๋ฅผ ํํํ๊ฒ ๋ง๋ค์ด์ฃผ๋ ๊ฒ : flatMap ๊ณ์ด ํจ์
-
flatMapConcat: ์์ฐจ์ ์ผ๋ก ์ฐ๊ฒฐ
-
flatMapMerge: ๋ณ๋ ฌ๋ก ์ฐ๊ฒฐ
-
flatMapLatest: ๊ฐ์ฅ ๋ง์ง๋ง ๊ฒ๋ง ์ ์ง
ex) ๊ฒ์์ด ์๋์์ฑ ๊ฐ์ ๊ธฐ๋ฅ์์๋ ์ฌ์ฉ์๊ฐ ์
๋ ฅ์ ๋ฐ๊ฟ ๋๋ง๋ค ์๋ก์ด API ํธ์ถ์ด ํ์=> flatMapLatest๋ฅผ ์ฃผ๋ก ์ฌ์ฉ
ํซ ํ๋ก์ ์ฝ๋ ํ๋ก์ ์ฐจ์ด
- Flow๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฝ๋
=> ๊ตฌ๋
์๊ฐ collectํ ๋๋ง๋ค ์๋กญ๊ฒ ์คํ
- StateFlow์ SharedFlow๋ ํซ ํ๋ก
=> ํ ๋ฒ ๋ฐฉ์ถ๋ ๋ฐ์ดํฐ๋ฅผ ๊ณ์ํด์ ์ฌ๋ฌ ๊ตฌ๋
์์๊ฒ ์ ๋ฌ ๊ฐ๋ฅ
- ํซ ํ๋ก๋ ์ด๋ฏธ ์คํ ์ค์ธ ์ํ๋ฅผ ๊ณต์ ํด์ผ ํ ๋ ์ฌ์ฉ
ex) ๋ก๊ทธ์ธ ์ํ, ๋ฒํผ ํด๋ฆญ ์ด๋ฒคํธ ๋ฑ
์ฝ๋ Flow๋ฅผ ํซ Flow๋ก ์ ํํ๊ธฐ
- shareIn() ๋๋ stateIn() ๊ฐ์ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ๋ฉด ๊ธฐ์กด์ ์ฝ๋ Flow๋ฅผ ํซ Flow๋ก ์ ํ ๊ฐ๋ฅ
=> Flow๋ฅผ ํ ๋ฒ๋ง ์คํํ๊ณ ์ฌ๋ฌ ๊ตฌ๋
์๊ฐ ๊ฐ์ ๊ณต์ ๊ฐ๋ฅ
val hotFlow = coldFlow.shareIn(scope, SharingStarted.Eagerly)
๐ SharedFlow
SharedFlow๋?
- ์ผํ์ฑ ์ด๋ฒคํธ๋ฅผ ์ฌ๋ฌ ๊ตฌ๋
์์๊ฒ ์ ๋ฌํ ์ ์๋ ํซ ํ๋ก
- ํ ์คํธ ๋ฉ์์ง, ๋ค๋น๊ฒ์ด์
์ด๋, ๋ค์ด์ผ๋ก๊ทธ ํ์์ฒ๋ผ UI ์ด๋ฒคํธ์ ์ ํฉ
- StateFlow์๋ ๋ฌ๋ฆฌ ๊ฐ์ ๊ธฐ์ตํ์ง ์๊ณ , emit() ํ๋ฉด ๊ตฌ๋
์ค์ธ ์ปดํฌ๋ํธ๋ง ๋ฐ์ดํฐ๋ฅผ ๋ฐ์
SharedFlowDemo ํ๋ก์ ํธ ๊ตฌ์ฑ
-
ViewModel์ MutableSharedFlow๋ฅผ ์ ์ธ
-
๋ฒํผ ํด๋ฆญ ๋ฑ์ผ๋ก emit() ์คํ
-
Composable์์๋ LaunchedEffect๋ก ์์ง
=> ์ด๋ฒคํธ์ฑ ๋ฐ์ดํฐ๋ฅผ UI์ ์ฐ๊ฒฐํ ๋ ์ง๊ด์
Compose์์ SharedFlow ์์ง
- Compose์์ SharedFlow๋ฅผ ์์งํ ๋ LaunchedEffect(Unit) ๋ธ๋ก ์ฌ์ฉ
- ์ปดํฌ๋ํธ๊ฐ ์ฒ์ ๋ํ๋ ๋ ํ ๋ฒ ์คํ๋๊ณ , ๋ด๋ถ์์ collect()๋ฅผ ํตํด ์ด๋ฒคํธ๋ฅผ ๊ฐ์ง
- ๋ฒํผ ํด๋ฆญ ์ ์ด๋ฒคํธ ๋ฐ์ โ Toast ํ์ ๊ฐ์ ๋ก์ง์ด ์์ฐ์ค๋ฝ๊ฒ ๊ตฌํ
- Flow๋ ์์ฐจ์ ๋ฐ์ดํฐ ํ๋ฆ์ ์ํ ์ฝ๋ฃจํด ๊ธฐ๋ฐ ๋๊ตฌ
- collectAsState๋ก Compose์ ์ฐ๋ ๊ฐ๋ฅ
- map, filter, buffer, combine, flatMapLatest ๋ฑ ๋ค์ํ ์ฐ์ฐ์ ์ ๊ณต
- SharedFlow๋ ์ผํ์ฑ UI ์ด๋ฒคํธ ์ฒ๋ฆฌ์ ์ต์
- Compose์์๋ LaunchedEffect๋ก SharedFlow ์์ง