๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ“ฑ| Android/๐Ÿš€ | Jetpack

[Android, Kotlin] compose์—์„œ api ํ†ต์‹ ํ•˜๊ธฐ

by immgga 2023. 8. 3.

 

์ด์ „ ํฌ์ŠคํŒ…์˜ ์—ฐ์žฅ์„ ์ž…๋‹ˆ๋‹ค.

https://rkdrkd-history.tistory.com/55

 

[Android, Kotlin] Android clean architecture ํ”„๋กœ์ ํŠธ์—์„œ api ์—๋Ÿฌ ํ•ธ๋“ค๋งํ•˜๊ธฐ

clean architecture ํ”„๋กœ์ ํŠธ๋ฅผ ๊ตฌ์ƒํ•˜๊ณ  ๊ฐœ๋ฐœํ•˜๋‹ค ๋ณด๋ฉด api error ์ฒ˜๋ฆฌ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•˜๊ณ  ์žˆ๋Š”๊ฐ€? ์˜ˆ์ „์˜ ํ•„์ž๋Š” ๊ทธ๋ƒฅ ๋ฌด์ง€์„ฑ์œผ๋กœ(?) presentation layer์— try catch๋ฅผ ์ด์šฉํ•ด ์ฒ˜๋ฆฌ๋ฅผ ํ–ˆ์—ˆ์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ ๋ฐฉ๋ฒ•์„

rkdrkd-history.tistory.com

 

์ด์ „ ํฌ์ŠคํŒ…์—์„œ clean architecture ๊ด€์ ์—์„œ api error handling ๋ฐฉ๋ฒ•์„ ๊ณต๋ถ€ํ•ด ๋ดค๋Š”๋ฐ,

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์ง€๋‚œ ๊ธ€์˜ ์—ฐ์žฅ์„ ์ธ clean architecture ๊ด€์ ์—์„œ compose๋กœ api ํ†ต์‹ ๋ฒ•์„ ์ ์–ด๋ณด๊ฒ ๋‹ค.

์‚ฌ์‹ค ํ•œ ํฌ์ŠคํŒ…์— ๋ชจ๋‘ ๋‹ด์„ ์ƒ๊ฐ์ด์—ˆ์ง€๋งŒ, ์ฃผ์ œ ์ฐจ์ด๋„ ์žˆ๊ณ  ๊ธ€์ด ๋„ˆ๋ฌด ๊ธธ์–ด์งˆ ๋“ฏํ•ด์„œ ๋‘ ๊ฐœ๋กœ ๋‚˜๋ˆˆ ์  ์ดํ•ดํ•ด ์ฃผ์‹œ๊ธธ xD

 

1. viewModel parameter ์ƒ์„ฑ

compose์—์„œ viewmodel์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด screen ํ•จ์ˆ˜์— viewmodel ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ดˆ๊ธฐํ™” ํ›„ ์‚ฌ์šฉํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

@Composable
fun MainScreen(
    twitchAuthViewModel: TwitchAuthViewModel = hiltViewModel()
) {
	. . . 
}

ํ˜„์žฌ clean architecture๋กœ ๊ฐœ๋ฐœ์„ ํ•˜๊ณ  ์žˆ๊ณ , ์˜์กด์„ฑ ์ฃผ์ž… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” hilt๋ฅผ ์‚ฌ์šฉ ์ค‘์ด๊ธฐ์— hiltViewModel()์„ ์‚ฌ์šฉํ•ด ์ฃผ์—ˆ๋‹ค.

hiltViewModel์€ navigation compose library๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

"androidx.navigation:navigation-compose:2.6.0"	// 2023-08-01 ๊ธฐ์ค€

์ด์ œ ์ƒ์„ฑํ•œ hiltViewModel์„ ์ด์šฉํ•ด api ํ˜ธ์ถœ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด ๋ณด๊ฒ ๋‹ค.

 

๋‹ค์Œ ์ฝ”๋“œ๋Š” mainScreen ์ „์ฒด ์ฝ”๋“œ์ด๋‹ค

@Composable
fun MainScreen(
    twitchAuthViewModel: TwitchAuthViewModel = hiltViewModel()
) {
    LaunchedEffect(Unit) {
        twitchAuthViewModel.getOAuthToken(
            clientId = BuildConfig.CLIENT_ID,
            clientSecret = BuildConfig.CLIENT_SECRET,
            grantType = "client_credentials"
        )
    }
    val oAuthToken by twitchAuthViewModel.oAuth.observeAsState()

    Column(modifier = Modifier.fillMaxSize()) {
        when (val data = oAuthToken) {
            ApiState.Loading -> {}
            is ApiState.Success -> {
                Text(text = "accessToken: ${data.data?.accessToken}")
                Text(text = "tokenType: ${data.data?.tokenType}")
                Text(text = "expiresIn: ${data.data?.expiresIn}")
            }
            ApiState.BadRequest -> Text(text = "bad request")
            ApiState.Forbidden -> Text(text = "forbidden")
            ApiState.TimeOut -> Text(text = "time out")
            ApiState.Server -> Text(text = "server error")
            ApiState.Unknown -> Text(text = "unknown")
            else -> Text(text = "else")
        }
    }
}

launchedEffect(Unit)๋ฅผ ์ด์šฉํ•ด api ๋กœ์ง์ด ํ•œ ๋ฒˆ๋งŒ ์ˆ˜ํ–‰๋˜๊ฒŒ ํ•˜์˜€๋‹ค.

๊ทธ๋ฆฌ๊ณ  observeAsState๋ฅผ ์ด์šฉํ•ด twitchAuthViewModel.oAuth์„ observing ํ•˜๋ฉด์„œ๋„ state๋ฅผ ๊ฐ€์ ธ์™€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์˜€๋‹ค.

when์„ ์ด์šฉํ•ด ApiState ์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๋กœ์ง์ด ํ˜ธ์ถœ๋˜๊ฒŒ ํ•˜์˜€๋‹ค.

 

2. ์ˆ˜ํ–‰ ๊ฒฐ๊ณผ

api ํ˜ธ์ถœ์ด ์ •์ƒ์ ์œผ๋กœ ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ •๋ฆฌ


compose๋กœ api ํ†ต์‹ ์„ ๊ณต๋ถ€ํ•ด ๋ดค๋Š”๋ฐ observing ํ•˜๋ฉด์„œ data state๋ฅผ ์“ธ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด ํŽธ๋ฆฌํ•œ ๊ฒƒ ๊ฐ™์•˜๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋‚˜์ค‘์— ์‚ฌ์šฉํ•  api๊ฐ€ ๋งŽ์•„์ง€๋ฉด, when ๋ฌธ์ด ๋งŽ์•„์ ธ ์ฝ”๋“œ๊ฐ€ ๋”๋Ÿฌ์›Œ์งˆ ๊ฒƒ ๊ฐ™์•„์„œ ํ•ด๊ฒฐํ•  ๋ฐฉ๋ฒ•์„ ์ƒ๊ฐํ•ด๋ด์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค.

 

์ฐธ๊ณ 

https://arca.live/b/twitchdev/44459710

 

* ํŠธ์œ„์น˜ API ๊ฐ€์ด๋“œ * - ํŠธ์œ„์น˜๊ฐœ๋ฐœ ์ฑ„๋„

0. Introduction (์„œ๋ก )ํŠธ์œ„์น˜ API๋ฅผ ์ฒ˜์Œ ์ ‘ํ•ด๋ณด๊ฑฐ๋‚˜ ์ฒ˜์Œ ์ด์šฉํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•œ ๊ฐ€์ด๋“œ ์ž…๋‹ˆ๋‹ค.์Šค์ฝ”ํ”„๊ฐ€ ํ•„์š” ์—†๊ณ  ์•ฑํ† ํฐ์„ ์‚ฌ์šฉํ•˜๋Š” ํŠธ์œ„์น˜ api ๋งŒ ๋‹ค๋ฃจ๊ฒ ์Šต๋‹ˆ๋‹ค.์˜์–ด ๋ฌธ์„œ๋งŒ ๋ณด๋ฉด ๊ดด๋ฆฌ๊ฐ์„ ๋Š

arca.live

728x90

๋Œ“๊ธ€