๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿค์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐœ๋ฐœ ๊ธฐ๋ก/๊ธฐ์ˆ™์‚ฌ ํ”„๋กœ์ ํŠธ ๊ธฐ๋ก

๐ŸŒžandroid compose์—์„œ ๋‚ ์”จ api๋ฅผ ์—ฐ๋™ํ•ด๋ณด์ž!

by hyeonha 2024. 2. 1.

 

android compose์—์„œ ๋‚ ์”จ api๋ฅผ ์—ฐ๋™ํ•˜๋Š” ๊ณผ์ •์„ ๊ธฐ๋กํ•ด๋ณด์•˜๋‹ค.  

 

1.JSON response์˜ Data Class๋ฅผ ์ •์˜ํ•ด์ค€๋‹ค.

<?xml version="1.0" encoding="UTF-8"?>
<response>
    <header>
        <resultCode>0</resultCode>
        <resultMsg>NORMAL_SERVICE</resultMsg>
    </header>
    <body>
        <dataType>XML</dataType>
        <items>
            <item>
                <baseDate>20210628</baseDate>
                <baseTime>0500</baseTime>
                <category>TMP</category>
                <fcstDate>20210628</fcstDate>
                <fcstTime>0600</fcstTime>
                <fcstValue>21</fcstValue>
                <nx>55</nx>
                <ny>127</ny>
            </item>
        </items>
        <numOfRows>10</numOfRows>
        <pageNo>1</pageNo>
        <totalCount>742</totalCount>
    </body>
</response>

 

๋‚ ์”จ ๋ฐ์ดํ„ฐ์˜ response๋Š” ์œ„์™€ ๊ฐ™์•˜๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋ฅผ ์œ„ํ•ด ์•„๋ž˜์™€ ๊ฐ™์ด dataClass๋ฅผ ์ •์˜ํ•ด์ฃผ์—ˆ๋‹ค. 

๋จผ์ € ํฐ ํ‹€์˜ data class๋ฅผ ์ •์˜ํ•ด์ฃผ๊ณ  ๋‚ด๋ถ€์˜ ์ž‘์€ data class๋ฅผ ์ •์˜ํ•ด์ฃผ๋ฉด ๋œ๋‹ค! 

 

๊ถ๊ธˆํ•œ ์  : ์ด ๋•Œ numOfRows์™€ pageNo์™€ totalCount์— ๋Œ€ํ•ด์„œ๋Š” ๋”ฐ๋กœ ์ •์˜ํ•ด์ฃผ์ง€ ์•Š์•„๋„ ์ž˜ ๋™์ž‘ํ•˜๋Š” ์ด์œ ๊ฐ€ ๊ถ๊ธˆํ•˜๋‹ค. 

package com.example.sejong2washertimer.data

data class Weather(
    val response: Response
) {
    data class Response(
        val header : Header,
        val body : Body
    ) {
        data class Header(
            val resultCode : Int,
            val resultMessage : String,
        )
        data class Body(
            val dataType : String,
            val items : Items
        ){
            data class Items(
                val item : List<Item>
            ){
                data class Item(
                    val baseDate : Int,
                    val baseTime : Int,
                    val category: String,
                    val fsctDate : Int,
                    val fcstTime : Int,
                    val fcstValue : Int,
                    val nx : Int,
                    val ny : Int
                )
            }

        }
    }
}

2. Retrofit interface๋ฅผ ๋งŒ๋“ ๋‹ค : @Query์˜ ์šฉ๋„ 

- URL endpoint๋ฅผ ์ด์šฉํ•œ๋‹ค.

- ๋น„๋™๊ธฐ ํ•จ์ˆ˜

interface WeatherApi {
    @GET("getVilageFcst?serviceKey=$API_KEY")
    suspend fun getWeather(
        @Query("dataType") dataType : String,
        @Query("numOfRows") numOfRows : Int,
        @Query("pageNo") pageNo : Int,
        @Query("base_date") baseDate : Int,
        @Query("base_time") baseTime : Int,
        @Query("nx") nx : String,
        @Query("ny") ny : String
    ) : Response<Weather>
}

 

๊ถ๊ธˆํ•œ ์  : @Query๋Š” ์™œ ์ ์–ด์ค˜์•ผํ• ๊นŒ? 

๊ทธ๋ž˜์„œ @Query๋ถ€๋ถ„์„ ์ฃผ์„ ์ฒ˜๋ฆฌ ํ•œ ํ›„ ์‹คํ–‰ํ•ด๋ณด์•˜๋‹ค. ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ None of the following functions can be called with the arguments supplied ์—๋Ÿฌ๊ฐ€ ๋–ด๋‹ค.

 

์˜ˆ์ƒํ•ด๋ณธ Query์˜ ๊ธฐ๋Šฅ์€ @Query์— ์ ์–ด์ฃผ๋Š” ๋ณ€์ˆ˜๋ฅผ ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ ์ธ์ž๋กœ ๋„˜๊ฒจ์ค˜์•ผํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค! 

์ฐพ์•„๋ณธ Query์˜ ๊ธฐ๋Šฅ์€ ์ด ๋งค๊ฐœ๋ณ€์ˆ˜๋“ค์ด HTTP ์š”์ฒญ์˜ ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์œผ๋กœ ๋งคํ•‘๋˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด๋‹ค

์ฆ‰ ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์š”์ฒญ์„ ํ•  ๋•Œ ํ•จ์ˆ˜์— ์ „๋‹ฌํ•˜๋Š” ๊ฐ’๋“ค์ด HTTP ์š”์ฒญ์˜ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋“ค์–ด๊ฐ„๋‹ค.

 

์•„๋ž˜์˜ ์—๋Ÿฌ๋Š” ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ํ•„์š”ํ•œ๋ฐ ์ „๋‹ฌ๋˜์ง€ ์•Š์•˜์Œ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.

 

3. Retrofit ๊ฐ์ฒด๋ฅผ ์–ป๊ธฐ ์œ„ํ•œ ํŒŒ์ผ

- retrofit ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜ ์ƒ์„ฑ

object RetrofitHelper {

    fun provideRetrofit(): Retrofit =
        Retrofit.Builder()
            .baseUrl(WEATHER_BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()

    fun provideWeatherApi(retrofit: Retrofit): WeatherApi =
        retrofit.create(WeatherApi::class.java)
}

 

 

- provideRetrofit ํ•จ์ˆ˜๋Š” Retrofit ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ตฌ์„ฑํ•œ๋‹ค. 

 

4. ๋ ˆํŠธ๋กœํ• ๊ฐ์ฒด์™€ ๋ ˆํŠธ๋กœํ• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์—ฐ๊ฒฐํ•ด์ค€๋‹ค.

- provideWeatherApi ํ•จ์ˆ˜๋Š” Retrofit ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ WeatherApi ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์ค๋‹ˆ๋‹ค .

 

5. Repository ์ƒ์„ฑํ•ด์ฃผ๊ธฐ 

๋ฐ์ดํ„ฐ ๋ช…๋ น์–ด๋ฅผ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•œ repository class๋ฅผ ์ƒ์„ฑํ•ด์ค€๋‹ค. 

@Singleton
class WeatherRepository  @Inject constructor(
    private val weatherApi: WeatherApi
) {
    suspend fun getWeather(
        dataType:String,
        numOfRows:Int,
        pageNo:Int,
        baseDate:Int,
        baseTime:Int,
        nx:String,
        ny:String
    ) : Response<Weather> {
        return weatherApi.getWeather(dataType,numOfRows,pageNo,baseDate,baseTime,nx,ny)
    }
}

 

6. ViewModel ๊ตฌํ˜„ํ•˜๊ธฐ 

composable UI๋ฅผ ์œ„ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ  ์œ„ํ•œ viewModel์„ ๊ตฌํ˜„ํ•ด์ค€๋‹ค.

@HiltViewModel
class WeatherViewModel  @Inject constructor(

    private val repository : WeatherRepository):ViewModel() {
    private val _weatherResponse: MutableLiveData<Response<Weather>> = MutableLiveData()
    private val _temperature : MutableState<String> = mutableStateOf("")
    @DrawableRes private var _weatherImageResource : MutableState<Int> = mutableIntStateOf(R.drawable.sunny)

    val temperature :MutableState<String> get() = _temperature

    val weatherImageResource : MutableState<Int> get() = _weatherImageResource

 

    fun makeWeatherRequest(
        dataType: String, numOfRows: Int, pageNo: Int,
        baseDate: Int, baseTime: Int, nx: String, ny: String
    ) {
        viewModelScope.launch {
            try {
                val response =
                    repository.getWeather(dataType, numOfRows, pageNo, baseDate, baseTime, nx, ny)
                _weatherResponse.value = response

                updateTemperature(response.body()?.response?.body?.items?.item)


            }
            catch (e:Exception){
                Log.d("๋‚ ์”จ", e.toString())

            }

        }

    }

 

 

    private fun updateTemperature(items: List<Weather.Response.Item>?) {
        if ((items != null) && items.isNotEmpty()) {
        
                    val filteredItems = items.filter {
                        it.category in listOf("TMP")
                    }

                    for (i in filteredItems) {
                    	// ํ˜„์žฌ ๊ธฐ์˜จ
                        if (i.category == "TMP") {
                            val temperature = i.fcstValue + "ยฐC"
                            _temperature.value = temperature
                        }
                        //๊ฐ•์ˆ˜ ์ฒ˜๋ฆฌ
                        if (i.category == "PTY") {
                            if (i.fcstValue == "1" || i.fcstValue == "4") {
                                rainStateText = "๋น„"
                                _weatherImageResource.value = R.drawable.rainy
                            }
                            if (i.fcstValue == "2") {
                                rainStateText = "๋น„/๋ˆˆ"
                                _weatherImageResource.value = R.drawable.rainy_snow
                            }
                            if (i.fcstValue == "3") {
                                rainStateText = "๋ˆˆ"
                                _weatherImageResource.value = R.drawable.snowy
                            }

                        }

                    }
                }
        }

7. Composabe UI ๋งŒ๋“ค์–ด์ฃผ๊ธฐ :  rememberUpdatedState

์•ฑ๋ฐ”์—์„œ ๋‚ ์”จ ์œ„์ ฏ์„ ๊ตฌํ˜„ํ•ด์ฃผ๊ธฐ ์œ„ํ•˜์—ฌ Main ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ์—ˆ๋‹ค. 

์—ฌ๊ธฐ์„œ rememberUpdateState๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์•Œ๊ฒŒ๋˜์—ˆ๋‹ค! 

val imageResource by rememberUpdatedState(newValue = weatherViewModel.weatherImageResource)
 Icon(
      painterResource(imageResource.value),
      contentDescription = "weather"
)
val temperature by rememberUpdatedState(newValue = weatherViewModel.temperature)
      Text(
           text = temperature.value,
           fontSize = 10.sp
 )

 

rememberUpdatedState ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‚ ์”จ ์ƒํƒœ์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด ์ด ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ถ€๋ถ„๋งŒ ๋‹ค์‹œ ๊ทธ๋ ค์ง„๋‹ค๊ณ  ํ•œ๋‹ค! 

 

์ดํ›„์— ๋‚ ์”จ ์œ„์ ฏ์— ์ „๋‹ฌ๋˜๋Š” ๋‚ ์งœ์™€ ์‹œ๊ฐ„ ๊ฐ’ ๋กœ์ง์„ ์ถ”๊ฐ€ํ•œ ๋’ค ๊ฒฐ๊ณผ๋ฅผ ๋ด์•ผ๊ฒ ๋‹ค

 

๊ฐ™์ด ๋ณด๋ฉด ์ข‹์€ ์ž๋ฃŒ

https://developer.android.com/jetpack/compose/side-effects?hl=ko#rememberupdatedstate

 

์‚ฌ์ง„ ์ถœ์ฒ˜

์ž‘๊ฐ€ macrovector</a> ์ถœ์ฒ˜ Freepik

728x90