와챠의 우당탕탕 코딩 일기장
[안드로이드] 최신 기상청 단기예보 API 활용하기(초단기예보, Json) 본문
올해 1학기 때 과제로 기상청 동네 예보 API를 사용한 적이 있었는데...
7월 초에 이런 메일이 왔다.
동네 예보 API가 종료된다고...
물론 단기 예보 단위가 상세화 되는 건 좋다~
기존에 있던 코드 바꾸는 게 귀찮을 뿐임
암튼 잘 쓰고 있던 API라 수정도 해보고 위젯같은 기능들도 추가해보려고 한다!!
일단 바뀐 API 부터 적용해보자.
나는 기존 API에서는 4시간 단위로 날씨 정보를 주는 동네예보를 사용했는데,
변경된 API에서는 1시간 단위로 날씨 정보를 주는 초단기예보를 사용해서 앱을 만들어보려고 한다!!
코드에 주석으로 간단히 설명했고 자세한 설명은 블로그 아래에 써놨다.
근데 전에 게시글(이전 기상청 동네 예보 API 사용)이랑 비슷한 부분이 많음!
https://min-wachya.tistory.com/129
실행 결과
현재 시간대 날씨 정보 1개 + 1시간 뒤의 날씨 정보가 5개씩해서 총 6개의 날씨 정보가 보여지는 것부터...시작했다.
그리고 각 온도에 맞춰서 옷 추천하는 것도 넣어봤다. 옷 추천은 나중에 위젯에도 활용할 거임!
먼저 공공데이터 포탈에서 활용신청 하기
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"/> 추가
3)
액션바 안 보이게 하기
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
(위젯 부분은 나중에 다룸)
grable(:app) 설정하기
Json 데이터를 쉽게 가져오기 위해
implementation 'com.squareup.retrofit2:retrofit:2.8.0'
implementation 'com.squareup.retrofit2:converter-gson:2.8.0' 추가
activity_main.xml : 앱 실행 시 보이는 첫 화면
list_item_weather.xml : 리사이클러뷰에 들어갈 아이템뷰
ModelWeather.kt : 날씨 정보가 담길 클래스
WeatherAdpater.kt : 리사이클러뷰에 들어갈 아이템뷰 설정해주는 부분
WeatherInterface.kt : xml 접근 준비 & xml 파일 형식 data class로 구현한 부분
MainActivity.kt : API 가져와서 ModelWeather에 날씨 정보 넣고 리사이클러뷰 설정한 부분
1, WeatherInterface에서 retrofit 설정할 때 baseUrl은 공공 데이터 포탈에서 아래 주소를 복붙하면 됨
baseUrl("http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/")
~이제부턴 제공된 문서 참고~
2, 나는 이중에 "초단기 예보 조회"를 사용해서 WeatherInterface에서 @GET 부분에 getUltraSrtFcst를 썼다.
// getUltraSrtFcst : 초단기 예보 조회 + 인증키
@GET("getUltraSrtFcst?serviceKey=서비스키_여기에_")
3, 데이터를 요청할 때 아래의 정보가 필요한데
이 작업은 WeatherInterface에서 이렇게 정의하고
fun GetWeather(@Query("numOfRows") num_of_rows : Int, // 한 페이지 경과 수
@Query("pageNo") page_no : Int, // 페이지 번호
@Query("dataType") data_type : String, // 응답 자료 형식
@Query("base_date") base_date : String, // 발표 일자
@Query("base_time") base_time : String, // 발표 시각
@Query("nx") nx : String, // 예보지점 X 좌표
@Query("ny") ny : String) // 예보지점 Y 좌표
: Call<WEATHER>
부르는 건 MainActivity에서 하게 했다.
// 날씨 정보 가져오기
// (한 페이지 결과 수 = 60, 페이지 번호 = 1, 응답 자료 형식-"JSON", 발표 날싸, 발표 시각, 예보지점 좌표)
val call = ApiObject.retrofitService.GetWeather(60, 1, "JSON", base_date, base_time, nx, ny)
4, 요청받은 데이터는 아래의 응답을 주는데,
나는 노란 밑줄친 부분만 필요해서 MainActivity에
// xml 파일 형식을 data class로 구현
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, val totalCount : Int)
data class ITEMS(val item : List<ITEM>)
// category : 자료 구분 코드, fcstDate : 예측 날짜, fcstTime : 예측 시간, fcstValue : 예보 값
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가 있고... 이런 식이다.
// xml 파일 형식을 data class로 구현
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, val totalCount : Int)
data class ITEMS(val item : List<ITEM>)
// category : 자료 구분 코드, fcstDate : 예측 날짜, fcstTime : 예측 시간, fcstValue : 예보 값
data class ITEM(val category : String, val fcstDate : String, val fcstTime : String, val fcstValue : String)
6, item의 category에는 아래의 코드값이 오는데, 나는 노란색 부분만 필요해서
이렇게 클래스를 만들어서
// 날씨 정보를 담는 데이터 클래스
class ModelWeather {
var rainType = "" // 강수 형태
var humidity = "" // 습도
var sky = "" // 하능 상태
var temp = "" // 기온
var fcstTime = "" // 예보시각
}
각 시간대의 날씨 정보를 배열 담았다.
// 배열 채우기
var index = 0
val totalCount = response.body()!!.response.body.totalCount - 1
for (i in 0..totalCount) {
index %= 6
when(it[i].category) {
"PTY" -> weatherArr[index].rainType = it[i].fcstValue // 강수 형태
"REH" -> weatherArr[index].humidity = it[i].fcstValue // 습도
"SKY" -> weatherArr[index].sky = it[i].fcstValue // 하늘 상태
"T1H" -> weatherArr[index].temp = it[i].fcstValue // 기온
else -> continue
}
index++
}
// 각 날짜 배열 시간 설정
for (i in 0..5) weatherArr[i].fcstTime = it[i].fcstTime
index를 6의 나머지인 0~5으로 고정한 이유는 6개의 배열을 인덱스 에러 없이 채우기 위해서임
7, 아래의 정보로 강수 형태와 하늘 상태에 대한 string값을 정했다.
// 강수 형태
tvRainType.text = getRainType(item.rainType)
// 하늘 상태
tvSky.text = getSky(item.sky)
// 강수 형태
fun getRainType(rainType : String) : String {
return when(rainType) {
"0" -> "없음"
"1" -> "비"
"2" -> "비/눈"
"3" -> "눈"
else -> "오류 rainType : " + rainType
}
}
// 하늘 상태
fun getSky(sky : String) : String {
return when(sky) {
"1" -> "맑음"
"3" -> "구름 많음"
"4" -> "흐림"
else -> "오류 rainType : " + sky
}
}
8, baseTime(예보자료 시각) 설정은 API 제공이 45분 이후니까
- 45분 이전이면 1시간 전으로 baseTime 설정하기
- 1자리면 2자리로 만들고 2자리면 시간 그대로 붙이기
- 분은 무조건 30분
이렇게 구현했다.
// baseTime 설정하기
private fun getBaseTime(h : String, m : String) : String {
var result = ""
// 45분 전이면
if (m.toInt() < 45) {
// 0시면 2330
if (h == "00") result = "2330"
// 아니면 1시간 전 날씨 정보 부르기
else {
var resultH = h.toInt() - 1
// 1자리면 0 붙여서 2자리로 만들기
if (resultH < 10) result = "0" + resultH + "30"
// 2자리면 그대로
else result = resultH.toString() + "30"
}
}
// 45분 이후면 바로 정보 받아오기
else result = h + "30"
return result
그리고 현재 시각이 00시라 1시간 전이 23시라면 어제 날짜로 baseDate도 변경했다.
// 현재 시각이 00시이고 45분 이하여서 baseTime이 2330이면 어제 정보 받아오기
if (timeH == "00" && base_time == "2330") {
cal.add(Calendar.DATE, -1).toString()
base_date = SimpleDateFormat("yyyyMMdd", Locale.getDefault()).format(cal.time)
}
9, 참고로 기온별 옷차림 추천 참고 자료는 이거
다음에 해볼 것
- 사용자 현재 위치 가져와서 위경도 값을 직접 좌표 값으로 변환
- 위젯 만들기
- 가로로 슬라이드하는 리사이클러뷰(?) 만들어보기
'코딩 일기장 > Android(Kotlin)' 카테고리의 다른 글
[안드로이드] 가로 슬라이드 리사이클러뷰 (0) | 2021.07.31 |
---|---|
[안드로이드] 사용자 위치 가져와서 날씨 정보 설정하기 (10) | 2021.07.30 |
[안드로이드] 갤러리에서 사진 가져오고 크롭하기(크기 조절하기) (6) | 2021.06.24 |
[안드로이드] 한국관광공사 Tour API 활용하기(지역기반 관광정보조회) - XML 데이터 가져오기 (0) | 2021.06.23 |
[안드로이드] 한국관광공사 Tour API 활용하기(지역기반 관광정보조회) - JSON 데이터 가져오기 (0) | 2021.06.23 |