Android
์๋๋ก์ด๋ Android ์ ๋๋ฉ์ด์ ์ผ๋ก Flow ์ดํดํ๊ธฐ
๋
ธ๋ฃจ๋ฃฝ
2024. 7. 21. 21:56
ํซ ์คํธ๋ฆผ
- ๋ฐ์ดํฐ๋ฅผ ์๋นํ๋ ๊ฒ๊ณผ ๋ฌด๊ดํ๊ฒ ์์๋ฅผ ์์ฑ
- Coroutines Channel
- ์ปฌ๋ ์ (List, Set)
์ฝ๋ ์คํธ๋ฆผ
- ์์ฒญ์ด ์์ ๋๋ง ์์ ์ ์ํ
- Sequence, Stream
- Flow, RxJava ์คํธ๋ฆผ
Flow
- Flow๋ฅผ ๋ฌด๊ธฐ ์์ดํ ๊ณต์ฅ ์์ ์๋ ์ปจ๋ฒ ์ด์ด ๋ฒจํธ๋ผ๊ณ ์๊ฐ๐จ
- ๊ฐ๊ฐ์ ์์ดํ ๋ค์ ๋ฐ์ดํฐ๋ผ๊ณ ์๊ฐ
- ๋ฌด๊ธฐ ์ ์ฅ๊ณ ์์ ๋ฌด๊ธฐ(๋ฐ์ดํฐ)๋ค์ ๋๋ค ํ๊ฒ ์ค์๊ฐ์ผ๋ก ์์ฑํ๊ณ , ๊ฐ ์ํฉ๋ค์ ์ ์ฅํด ๋ณด์!
sealed class Weapon {
class Sword(): Weapon()
class Staff(): Weapon()
class SpellBook(): Weapon()
}
Flow ์์ฑ
val weaponProducer: Flow<Weapon>
- Flow๋ฅผ ์์ฑํ๋ ์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ → ์ฝ๋ฃจํด ์ฑ๋์ produce์ ๋น์ทํ ํํ์ ๋น๋ flow ์ ์ธ
- Flow๋ ๊ฐ์ด ํ์ํ ๋๋ง ์์ฑํ๊ธฐ ๋๋ฌธ์,
๋ฐ์ง๊ณ ๋ณด๋ฉด ๋น๋๋ ์๋๊ณcollect() ๊ฐ์ ์ต์ข ์ฐ์ฐ ์ ๋ฐ์ดํฐ๊ฐ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ์ง ์ ์ํ ๊ฒ
Emit๊ณผ Collect
- ์๋ก์ด ๋ฌด๊ธฐ(๋ฐ์ดํฐ)๊ฐ ์์ฑ๋ ๋๋ง๋ค weaponProducer๋ emit() ํจ์๋ฅผ ํธ์ถํ๋ค.
- collect()๋ฅผ ํธ์ถํ์ฌ ๋ฌด๊ธฐ(๋ฐ์ดํฐ)๋ฅผ ์์
import kotlinx.coroutines.flow.flow
private val weaponProducer: Flow<Weapon> = flow {
emit(Weapon.Sword())
emit(Weapon.Staff())
emit(Weapon.SpellBook())
}
private val weaponBox = mutableListOf<Weapon>()
suspend fun main() {
weaponProducer.collect { weapon ->
weaponBox.add(weapon)
}
}
Kotlin Flow์ Operators ์ข ๋ฅ
- Terminal Operators
- Flow์ ์คํ์ ์์ํ๊ฑฐ๋ ์ต์ข ์์ ์ ์ํํ๋ ๋ฐ ์ฌ์ฉ
- collect(), first(), last() ๋ฑ
- Intermediate Operators
- ๋ฐ์ดํฐ๋ฅผ ๋ณํ, ํํฐ๋ง ๋๋ ์กฐ์
- Flow๋ฅผ ์คํํ์ง ์์ผ๋ฉฐ, ๋ฐ์ดํฐ๋ฅผ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ์ง ์ ์
- filter, map, transform ๋ฑ
Intermediate Operators
Filter
- ํน์ ์กฐ๊ฑด์ ์ถฉ์กฑํ๋ ์์๋ฅผ ์ ํ
- ๋ฌด๊ธฐ๊ฐ Sword์ธ ๊ฒฝ์ฐ๋ง collect()
weaponProducer
.filter { weapon ->
weapon is Sword
}.collect()
DistinctUntilChanged
- ์ฐ์๋ ์ค๋ณต ์์๋ฅผ ํํฐ๋ง
- ์ด์ ๊ฐ๊ณผ ๋ค๋ฅธ ๊ฒฝ์ฐ์๋ง emit ๊ฐ๋ฅ
weaponProducer
.distinctUntilChanged()
.collect()
Map
- ๊ฐ ์ ๋ ฅ ์์๋ฅผ ๋ณํํ๋ ๋ฐ ์ฌ์ฉ
- ์๋ Flow๋ Collection์ ๋ณ๊ฒฝํ์ง ์๊ณ , ๋ณํ๋ ๊ฐ์ผ๋ก ์๋กญ๊ฒ ๋ง๋ ๋ค.
- ์ผ๋ฐ ๋ฌด๊ธฐ(Weapon)์์ EnchantedWeapons๋ก ๋ณํ
weaponProducer
.map { weapon ->
mapToEnchantedWeapon(weapon)
}.collect()
FlatMap
- Map์ ๊ฐ ์์๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ๋ณํ
- FlatMap์ ๊ฐ ์์๋ฅผ ๋ค๋ฅธ Flow๋ก ๋ณํ ํ ์ด๋ค์ ๋ณํ
Map์ ๋ด๋ถ ๊ตฌํ
inline fun <T, R> Flow<T>.map(
crossinline transform: suspend (value: T) -> R
): Flow<R>
FlatMap์ ๋ด๋ถ ๊ตฌํ
inline fun <T, R> Flow<T>.flatMapLatest(
crossinline transform: suspend (value: T) -> Flow<R>
): Flow<R>
- ๊ฐ๊ฐ์ ์์๋ฅผ Flow๋ก ๋ฆฌํดํ ํ, ๊ทธ Flow๋ค์ ๋ณํฉ
val weaponTypes: Flow<WeaponType> = queryWeaponTypes()
private fun produceWeapons(weaponType: WeaponType): Flow<Weapon> {
// Emit weapons of the specified type
}
weaponTypes
.flatMap { type ->
produceWeapons(type)
}.collect()
- WeaponType์ด ๋ฐฉ์ถ๋๋ฉด์ Flow<Weapon>์ด ์์ฑ
Zip
- ๋ Flow๋ฅผ ๊ฒฐํฉํ์ฌ ๋์ํ๋ ์์๋ค์ Pair๋ก ๋ฌถ์ด ์๋ก์ด ์์๋ฅผ ์์ฑ
- Flow A์ ์ฒซ ๋ฒ์งธ ์์์ Flow B์ ์ฒซ ๋ฒ์งธ ์์๊ฐ ์ง์ ์ด๋ฃจ๊ณ , ๋ ๋ฒ์งธ ์์๋ผ๋ฆฌ ์ง์ ์ด๋ฃจ๊ณ . . .
- enchantments flow์ weapons flow๋ฅผ ๊ฒฐํฉํ์ฌ EnchentedWeapons๋ฅผ ์์ฑ
val enchantments: Flow<Enchantment> = queryEnchantments()
val weapons: Flow<Weapon> = queryWeapons()
enchantments.zip(weapons) { enchantment, weapon ->
createMagicWeapon(enchantment, weapon)
}
๊ฒฐ๋ก
Flow๋ฅผ ์๊ฐํํด์ ๋ณผ ์ ์์ด์ ์ฝ๊ณ ์ฌ๋ฐ๊ฒ ์ดํด๊ฐ ๊ฐ๋ฅํ๋ค! ๐
Flow๋ฅผ ์์ ์์ฌ๋ก ์ฌ์ฉํ๋ฉด ์ ๋ง ํธ๋ฆฌํ๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ค์๊ฐ์ผ๋ก ๋ฐ์ํ ์ ์์ ๊ฒ ๊ฐ๋ค!!
ํด๋น ํฌ์คํ ์ ์๋ฌธ์ ์๋ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํด ์ฃผ์ธ์.
Reference
https://medium.com/@robert.baricevicpetrus/kotlin-flows-animated-55640aa48ac9