와챠의 우당탕탕 코딩 일기장

[안드로이드] 기상청 동네예보 API 활용하기 본문

코딩 일기장/Android(Kotlin)

[안드로이드] 기상청 동네예보 API 활용하기

minWachya 2021. 5. 9. 16:50
반응형

아래의 앱을 만들어 볼 것이다.

원래는 흰 배경에 검정 글씨인데

지금 내 폰이 다크모드라 저렇게 됐다. 신기...

실행 결과

 


공공 데이터 포탈에서 아래 API를 검색한 후 활용 신청하기!!

 

AndroidManifest.xml 설정하기

 

1)

manifest-application에
android:usesCleartextTraffic="true" 추가

 

2)

인터넷과 네트워크 연결 위해서 아래의 퍼미션

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

추가

 

그러면 일케 된다.

AndroidManifest.xml

 

 

 

 

grable(:app) 설정하기

implementation 'com.squareup.retrofit2:retrofit:2.8.0'
implementation 'com.squareup.retrofit2:converter-gson:2.8.0'

추가!

 

 


 

 

일단 코드 먼저... 자세한 설명은 마지막에

 

activity_main.xml

 

 

 

WeatherInterface.kt

 

 

 

MainActivity.kt

 

 

 

 


 

 

 

1, MainActivity에서 32번째 줄에 사용된 링크는 공공 데이터 포탈에서 아래 주소를 복붙하면 된다.

baseUrl("http://apis.data.go.kr/1360000/VilageFcstInfoService/")

 

 

2, 나는 이중에 "동네 예보 조회"를 사용할 것이기 때문에 WeatherInterface의 10번째 줄에서 getVilageFcst를 적었다.

@GET("getVilageFcst?serviceKey=D")

 

 

3, 데이터를 요청할 때 아래의 정보가 필요한데 이 작업은 WeatherInterface에서 한다.

 

 

4, 요청받은 데이터는 아래의 응답을 주는데, 나는 노란 밑줄친 부분만 필요해서 MainActivity에 

data class ITEM(val category : String, val fcstDate : String, val fcstTime : String, val fcstValue : String)

위와 같이 적었다.

 

 

 

5, 응답 메시지의 xml은 아래와 같은데 이를 data class로 표현해주기 위해 아래와 같이 표현했다.

태그의 관계를 잘 살펴보면 이해하기 쉽다!

 

response 안에 header, body가 있고...heraer 안에 resultCode와 resultMsg가 있고... 이런 식이다.

data class WEATHER (val response : RESPONSE)
data class RESPONSE(val header : HEADER, val body : BODY)
data class HEADER(val resultCode : Int, val resultMsg : String)
data class BODY(val dataType : String, val items : ITEMS)
data class ITEMS(val item : List<ITEM>)

 

 

6, item에는 아래의 정보가 담겨져 오는데, 나는 노란색 부분만 필요해서

이렇게 표현해줬다.

 

for (i in 0..9) {
                        when(it[i].category) {
                            "POP" -> rainRatio = it[i].fcstValue    // 강수 기온
                            "PTY" -> rainType = it[i].fcstValue     // 강수 형태
                            "REH" -> humidity = it[i].fcstValue     // 습도
                            "SKY" -> sky = it[i].fcstValue          // 하늘 상태
                            "T3H" -> temp = it[i].fcstValue         // 기온
                            else -> continue
                        }

                    }

 

 

7, 아래의 정보로 강수 형태와 하늘 상태에 대한 string값을 정했다.

	// 강수 형태
	when(rainType) {
            "0" -> result = "없음"
            "1" -> result = "비"
            "2" -> result = "비/눈"
            "3" -> result = "눈"
            "4" -> result = "소나기"
            "5" -> result = "빗방울"
            "6" -> result = "빗방울/눈날림"
            "7" -> result = "눈날림"
            else -> "오류"
        }

        // 하늘 상태
        when(sky) {
            "1" -> result = "맑음"
            "3" -> result = "구름 많음"
            "4" -> result = "흐림"
            else -> "오류"
        }

 

 

8, 그리고 가장 헷갈렸던 건데 이 baseTime(예보자료 시각)과 fcstTime(발표 시간),,,

 

아래의 표를 보면 "발표시간 = 현재 시각 + 4"이란 것을 할 수 있다.

그니끼 현재 시간으로 데이터를 요청하면 현재시간대 + 4시간의 예보를 얻을 수 있는 것이다.

 

ex) 현재 시각이 0200이면,  +4시간이 된 0600의 예보를 받음

(2시 예보가 아닌 6시의 예보를 미리 받는 것)

 

그런데 나는 다음 시간대의 예보를 미리 받아보고 싶은 게 아닌 현재 시간대의 예보를 알고 싶어서 아래의 함수로 설정을 다시 해줬다.

만약 내가 6~8시 사이에 있고 6시 예보를 받고 싶다면 4시간 전인 2시로 baseTime을 설정해주어야 함...을 나타내는 표

base time fcst time 현재 시간대
0200 0600 06~08
0500 0900 09~11
0800 1200 12~14
1100 1500 15~17
1400 1800 18~20
1700 2100 21~23
2000 0000 00~02
2300 0300 03~05

 

fun getTime(time : String) : String {
        var result = ""
        when(time) {
            in "00".."02" -> result = "2000"    // 00~02
            in "03".."05" -> result = "2300"    // 03~05
            in "06".."08" -> result = "0200"    // 06~08
            in "09".."11" -> result = "0500"    // 09~11
            in "12".."14" -> result = "0800"    // 12~14
            in "15".."17" -> result = "1100"    // 15~17
            in "18".."20" -> result = "1400"    // 18~20
            else -> result = "1700"             // 21~23
        }
        return result
    }

 

 

 

그리고 현재 시각에 대한 정보를 얻으려면 현재시각 + 4시간을 해야하다보니까

오늘의 예보시각(fcst time) 0000의 예보를 보기 위해선 어제의 현재시각(base time) 2000 예보가 필요하다,,,

위 표의 이부분

base time (현재 시각) fcst time (예보 시각)
20000 0000
2300 0300

그래서 base_date도 하루를 빼주는....^^!!!

if (base_time >= "2000") {
            cal.add(Calendar.DATE, -1).toString()
            base_date = SimpleDateFormat("yyyyMMdd", Locale.getDefault()).format(cal.time)
        }

 

 

API 써보니까 넘 재밌다...

별 거 안 했는데 유용한 정보가 쏙쏙 나오는 이 기분...

땅을 팠는데... 고구마가 나온 기분

반응형
Comments