๐Ÿค” Android UI State, ์™œ Enum์ด ์•„๋‹ˆ๋ผ Sealed Class/Interface์ผ๊นŒ?

์ด์ง„์˜ยท2025๋…„ 9์›” 17์ผ
post-thumbnail

๐Ÿงฉ ์„ ์–ธํ˜• UI์™€ ์ƒํƒœ

Jetpack Compose ๊ฐ™์€ ์„ ์–ธํ˜• UI๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐœ๋ฐœ์ž๋Š” ์ƒํƒœ(State)๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ™”๋ฉด์„ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.

๊ธฐ์กด์˜ ๋ช…๋ นํ˜• UI(์˜ˆ: findViewById, setVisibility)์—์„œ๋Š”
"๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์ด ๋ทฐ๋ฅผ ์ˆจ๊ธฐ๊ณ , ๋‹ค๋ฅธ ๋ทฐ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค"๋ผ๋Š” ์‹์œผ๋กœ UI ์กฐ์ž‘ ๋กœ์ง์„ ์ง์ ‘ ์ž‘์„ฑํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์„ ์–ธํ˜• UI์—์„œ๋Š”
๐Ÿ‘‰ "ํ˜„์žฌ ์ƒํƒœ๊ฐ€ Loading์ด๋ฉด ๋กœ๋”ฉ ํ™”๋ฉด์„ ๊ทธ๋ ค๋ผ"
๐Ÿ‘‰ "ํ˜„์žฌ ์ƒํƒœ๊ฐ€ Success๋ผ๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ค˜๋ผ"
๐Ÿ‘‰ "ํ˜„์žฌ ์ƒํƒœ๊ฐ€ Error๋ผ๋ฉด ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•ด๋ผ"

์ฆ‰, UI๋Š” ์ƒํƒœ์˜ ์Šค๋ƒ…์ƒท์„ ๊ทธ๋ฆฌ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฐ”๋€Œ์—ˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์ƒํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ์ •์˜ํ•˜๋А๋ƒ๊ฐ€ ์•ฑ์˜ ๊ตฌ์กฐ์™€ ์•ˆ์ •์„ฑ์— ํฐ ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค.


โ“ ์™œ ์•„์ฃผ ๋‹จ์ˆœํ•œ ๊ตฌ์กฐ์ธ Enum์„ UI State๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„๊นŒ

์ฒ˜์Œ์—๋Š” ๋งŽ์€ ๋ถ„๋“ค์ด ์ด๋ ‡๊ฒŒ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
"์ƒํƒœ๋ฅผ ํ‘œํ˜„ํ•œ๋‹ค๋ฉด Enum์ด ๋”ฑ์ด์ง€ ์•Š๋‚˜? ๊ฐ’๋งŒ ๊ตฌ๋ถ„ํ•˜๋ฉด ๋˜์ž–์•„?"

enum class NetworkStatus(val code: Int, val description: String) {
    LOADING(0, "Loading..."),
    SUCCESS(200, "Request succeeded"),
    ERROR(500, "Internal server error");
}

์ด ์ฝ”๋“œ๋Š” ์–ผํ• ๋ณด๋ฉด ๊ทธ๋Ÿด์‹ธํ•ฉ๋‹ˆ๋‹ค.
๋„คํŠธ์›Œํฌ ์š”์ฒญ์˜ ์„ธ ๊ฐ€์ง€ ์ƒํƒœ๋ฅผ ์ž˜ ํ‘œํ˜„ํ•˜๊ณ  ์žˆ๊ณ , ์ˆซ์ž ์ฝ”๋“œ๋„ ๋ถ™์ผ ์ˆ˜ ์žˆ์ฃ .

ํ•˜์ง€๋งŒ ์‹ค์ œ UI๋ฅผ ๋งŒ๋“ค๋‹ค ๋ณด๋ฉด ๊ธˆ๋ฐฉ ํ•œ๊ณ„๋ฅผ ๋А๋ผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๐Ÿšจ ํ•œ๊ณ„ 1: ์ƒํƒœ๋ณ„๋กœ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์ด ์–ด๋ ต๋‹ค

  • SUCCESS ์ƒํƒœ์—์„œ๋Š” ์„œ๋ฒ„์—์„œ ๋‚ด๋ ค์ค€ ๋ฐ์ดํ„ฐ๋ฅผ UI์— ๋„˜๊ฒจ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ERROR ์ƒํƒœ์—์„œ๋Š” ๋‹จ์ˆœ ์ฝ”๋“œ(500)๋ฟ ์•„๋‹ˆ๋ผ, ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์ค„ ๋ฉ”์‹œ์ง€๋‚˜ ์˜ˆ์™ธ ๊ฐ์ฒด๋„ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

Enum์€ ๋ชจ๋“  ์ƒ์ˆ˜๊ฐ€ ๊ฐ™์€ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ ธ์•ผ ํ•˜๋ฏ€๋กœ,
์ƒํƒœ๋งˆ๋‹ค ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ๊ฐ–๊ฒŒ ํ•˜๊ธฐ๊ฐ€ ์‚ฌ์‹ค์ƒ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.


๐Ÿšจ ํ•œ๊ณ„ 2: UI ์ƒํƒœ๋Š” ์ข…์ข… โ€œ์—ด๋ฆฐ ์ง‘ํ•ฉโ€์ด ์•„๋‹ˆ๋‹ค

UI State๋Š” ๋ณดํ†ต "์ •ํ•ด์ง„ ๋ช‡ ๊ฐ€์ง€ ์ƒํƒœ"๋งŒ ์žˆ์œผ๋ฉด ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด ๋กœ๊ทธ์ธ ํ™”๋ฉด์ด๋ผ๋ฉด

  • Idle
  • Loading
  • Success
  • Error

์ด ์ •๋„๋ฉด ๋์ž…๋‹ˆ๋‹ค.
๊ทธ๋Ÿฐ๋ฐ Enum์€ ๋ณธ์งˆ์ ์œผ๋กœ "์—ด๋ฆฐ ๊ตฌ์กฐ"๋ผ๊ธฐ๋ณด๋‹ค๋Š”, ์ƒํƒœ๋ณ„๋กœ ๋ฐ์ดํ„ฐ๊นŒ์ง€ ๋‹ค๋ฃจ๊ธฐ์—๋Š” ๋„ˆ๋ฌด ๋‹จ์ˆœํ•œ ํ‹€์ด์ฃ .

์ฆ‰, Enum์€ UI State๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ์—” ํ‘œํ˜„๋ ฅ์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค.


โœ… Sealed Class โ€“ ์ƒํƒœ์™€ ๋ฐ์ดํ„ฐ๋ฅผ ํ•จ๊ป˜ ํ‘œํ˜„

๊ทธ๋ž˜์„œ ๋“ฑ์žฅํ•˜๋Š” ๊ฒŒ sealed class์ž…๋‹ˆ๋‹ค.
sealed class๋Š” ๋‹ซํžŒ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์ƒํƒœ์™€ ๋ฐ์ดํ„ฐ๋ฅผ ํ•จ๊ป˜ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

sealed class LoginUiState {
    object Idle : LoginUiState()
    object Loading : LoginUiState()
    data class Success(val userName: String) : LoginUiState()
    data class Error(val message: String, val code: Int? = null) : LoginUiState()
}

์—ฌ๊ธฐ์„œ ์ฃผ๋ชฉํ•  ์ ์€,
๊ฐ ์ƒํƒœ๊ฐ€ ์ž๊ธฐ์—๊ฒŒ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋งŒ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  • Loading โ†’ ๋ณ„๋„ ๋ฐ์ดํ„ฐ ํ•„์š” ์—†์Œ
  • Success โ†’ ์‚ฌ์šฉ์ž ์ด๋ฆ„ ํ•„์š”
  • Error โ†’ ๋ฉ”์‹œ์ง€์™€ ์—๋Ÿฌ ์ฝ”๋“œ ํ•„์š”

๐Ÿ’ก Compose์—์„œ์˜ ์‚ฌ์šฉ ์˜ˆ์‹œ

when (uiState) {
    is LoginUiState.Idle -> IdleScreen()
    is LoginUiState.Loading -> LoadingScreen()
    is LoginUiState.Success -> WelcomeScreen(uiState.userName)
    is LoginUiState.Error -> ErrorScreen(uiState.message)
}
  • when ๊ตฌ๋ฌธ์—์„œ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋ชจ๋“  ์ƒํƒœ๋ฅผ ๊ฐ•์ œ ์ฒดํฌํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์—,
    ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ถ„๊ธฐ๋ฌธ์—์„œ ๋ˆ„๋ฝ๋œ ๋ถ€๋ถ„์„ IDE๊ฐ€ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.
  • ์ด๋Š” ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๋ฅผ ์ปดํŒŒ์ผ ํƒ€์ž„์— ์žก์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฐ•๋ ฅํ•œ ์žฅ์ ์ž…๋‹ˆ๋‹ค.

๐Ÿ‘‰ ์ฆ‰, sealed class๋Š” UI State๋ฅผ ํ‘œํ˜„ํ•  ๋•Œ ์•ˆ์ „์„ฑ๊ณผ ๊ฐ€๋…์„ฑ์„ ๋™์‹œ์— ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


โšก Sealed Interface โ€“ ๋” ์œ ์—ฐํ•œ ํ™•์žฅ์„ฑ

sealed interface๋Š” sealed class์™€ ๊ฑฐ์˜ ๋น„์Šทํ•˜์ง€๋งŒ, ๋‹ค์ค‘ ์ƒ์†์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์ ์—์„œ ๋” ์œ ์—ฐํ•ฉ๋‹ˆ๋‹ค.

sealed interface UiState

object Loading : UiState
data class Success(val data: List<String>) : UiState
data class Error(val message: String) : UiState

๋‹ค๋ฅธ ์ธํ„ฐํŽ˜์ด์Šค์™€ ์กฐํ•ฉ ์˜ˆ์‹œ

interface Loggable {
    val log: String
}

data class Error(
    val message: String,
    override val log: String
) : UiState, Loggable

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Error๋Š” UI State์ด๋ฉด์„œ ๋™์‹œ์— Loggableํ•œ ์„ฑ๊ฒฉ๋„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ฆ‰, ์ƒํƒœ๋ฅผ ๋‹ค์–‘ํ•œ ๋งฅ๋ฝ์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ™•์žฅ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.


๐Ÿงฉ ์™œ sealed๊ฐ€ ์ค‘์š”ํ•œ๊ฐ€?

์—ฌ๊ธฐ์„œ ํ•ต์‹ฌ์€ sealed๋ผ๋Š” ํ‚ค์›Œ๋“œ ์ž์ฒด์ž…๋‹ˆ๋‹ค.

์ผ๋ฐ˜ class๋‚˜ interface๋Š” ์–ด๋””์„œ๋“  ์ƒ์†/๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
์ฆ‰, ์ƒํƒœ ์ง‘ํ•ฉ์ด ์—ด๋ ค(Open) ์žˆ์–ด์„œ ์™ธ๋ถ€์—์„œ ์ƒˆ๋กœ์šด ํ•˜์œ„ ํƒ€์ž…์ด ์ถ”๊ฐ€๋  ์ˆ˜ ์žˆ์ฃ .

UI State์—์„  ์ด๋Ÿฐ ๊ฒŒ ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค.
๋กœ๊ทธ์ธ ํ™”๋ฉด์˜ ์ƒํƒœ๋Š” Idle, Loading, Success, Error๋งŒ ์žˆ์œผ๋ฉด ๋˜๋Š”๋ฐ,
๋ˆ„๊ตฐ๊ฐ€ ์™ธ๋ถ€ ๋ชจ๋“ˆ์—์„œ HalfSuccess ๊ฐ™์€ ์ด์ƒํ•œ ์ƒํƒœ๋ฅผ ์ถ”๊ฐ€ํ•ด๋ฒ„๋ฆฌ๋ฉด?
๐Ÿ‘‰ when ๋ถ„๊ธฐ์—์„œ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ•œ ์ƒํƒœ๊ฐ€ ์ƒ๊ฒจ, ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

sealed๋ฅผ ์“ฐ๋ฉด:

  • ํ•˜์œ„ ํƒ€์ž…์„ ๊ฐ™์€ ํŒŒ์ผ ๋‚ด์—์„œ๋งŒ ์ •์˜ ๊ฐ€๋Šฅ โ†’ ์ƒํƒœ ์ง‘ํ•ฉ์ด ๋‹ซํž˜(Closed set)
  • ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ when์—์„œ ๋ชจ๋“  ์ƒํƒœ๋ฅผ ๊ฐ•์ œ ์ฒดํฌ โ†’ ๋ˆ„๋ฝ ๋ฐฉ์ง€

๐Ÿ“Œ ์ •๋ฆฌํ•˜์ž๋ฉด, sealed์˜ ๊ฐ€์žฅ ํฐ ์˜๋ฏธ๋Š” โ€œ์—ฌ๊ธฐ ์ •์˜๋œ ์ƒํƒœ ์™ธ์—๋Š” ์—†๋‹คโ€๋ฅผ ๋ณด์žฅํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด ๋•๋ถ„์— UI State๋ฅผ ์ •์˜ํ•  ๋•Œ sealed class/interface๊ฐ€ ๋น›์„ ๋ฐœํ•ฉ๋‹ˆ๋‹ค โœจ


๐Ÿ” ์ •๋ฆฌ

  • enum โ†’ ๋‹จ์ˆœ ์ƒํƒœ ๊ตฌ๋ถ„์— ์ ํ•ฉ (์˜ˆ: Theme { LIGHT, DARK })
  • sealed class โ†’ ์ƒํƒœ + ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์–ด UI State ๊ด€๋ฆฌ์— ์ตœ์ 
  • sealed interface โ†’ ๋‹คํ˜•์„ฑ๊ณผ ํ™•์žฅ์„ฑ์ด ํ•„์š”ํ•œ ์ƒํ™ฉ์—์„œ ์œ ๋ฆฌ
  • sealed โ†’ ์ƒํƒœ ์ง‘ํ•ฉ์„ ๋‹ซ์•„์ฃผ๊ณ , ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋ชจ๋“  ๊ฒฝ์šฐ๋ฅผ ๊ฐ•์ œ ์ฒดํฌํ•˜๊ฒŒ ํ•ด์คŒ

๐Ÿ‘‰ Compose์—์„œ UI State๋ฅผ ์ •์˜ํ•  ๋•Œ๋Š”
enum๋ณด๋‹ค sealed class/interface๋ฅผ ์“ฐ๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ์•ˆ์ „ํ•˜๊ณ  ํ‘œํ˜„๋ ฅ์ด ํ’๋ถ€ํ•ฉ๋‹ˆ๋‹ค ๐Ÿ’ก

UI State๋Š” ๊ณง ์•ฑ์˜ ์•ˆ์ •์„ฑ๊ณผ ์ง๊ฒฐ๋˜๋Š” ํ•ต์‹ฌ ์š”์†Œ์ž…๋‹ˆ๋‹ค.
์ž‘์€ ์„ ํƒ ํ•˜๋‚˜๊ฐ€ ์ „์ฒด ์•„ํ‚คํ…์ฒ˜์˜ ํ’ˆ์งˆ์„ ํฌ๊ฒŒ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ๐Ÿš€

profile
Android Developer

0๊ฐœ์˜ ๋Œ“๊ธ€