안녕하세요!
안드로이드 앱을 개발하다보면 서버와의 통신 작업이 많이 필요하게 되는데요
이때 정말 편하게 사용할 수 있는 라이브러리인 Retrofit을 소개해보려고 합니다.
이 글을 작성할 때
생각자유의 안드로이드 이야기 - Retrofit 기본 기능에 대해서 알아보자
이 글을 많이 참조하였습니다!
http://square.github.io/retrofit/
저는 Retrofit을 이용하여 날씨 정보를 가져오는 API 통신을 해보겠습니다.
https://developers.skplanetx.com/apidoc/kor/weather/
SKplanet 에서 제공하는 Weather Planet에서 정보를 받아오겠습니다.
먼저 build.gradle(Module : app) 에 다음과 같이 추가해줍니다.
dependencies {
compile 'com.squareup.retrofit2:retrofit:2.1.0' // Retrofit
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta3' // Gson 변환을 위한 converter
}
인터넷 통신을 하기 위해 퍼미션을 추가 해 줍니다.
<uses-permission android:name="android.permission.INTERNET"/>
이로써 Retrofit 을 사용하기 위한 준비가 끝났습니다.
이제 본격적으로 날씨 정보 얻어오기를 달려보겠습니다!
저는 현재날씨(시간별) 데이터를 받아보겠습니다.
Weather Planet 의 현재 날씨 API는 다음과 같은 양식으로 되어있습니다.
Resource URI
http://apis.skplanetx.com/weather/current/hourly?version={version}&lat={lat}&lon={lon}&city={city}&county={county}&village={village}
Protocol - REST
HTTP Method - GET
여기서
http://apis.skplanetx.com/ 은 baseURL
weather/current/hourly 는 현재날씨(시간별)에 해당하는 URL
? 뒤쪽 부분은 변수 명이 됩니다.
이를 이용하여 Interface Class를 선언해 보겠습니다
저는 WeatherRepo 클래스 안에 인터페이스를 선언하여 Call<WeatherRepo> 로 나오게 되었습니다.
WeatherRepo 클래스는 API 통신을 하며 데이터를 받는 객체 클래스로 아래에서 설명드리겠습니다.
버전 정보와 위도, 경도만 필요하기 때문에 country 와 village는 생략하였습니다.
public interface WeatherApiInterface {
@Headers({"Accept: application/json"})
@GET("weather/current/hourly")
Call<WeatherRepo> get_Weather_retrofit(@Query("version") int version, @Query("lat") String lat, @Query("lon") String lon);
}
이와 같이
@Headers 에는 필요한 헤더 부분을 ({ ~~ . ~~ }) 형식으로 넣어줄 수 있습니다.
@GET 부분에는 현재날씨(시간별)에 해당하는 URL 을 넣어줍니다.
다음으로 Call입니다.
Call <'주고받을 객체'> '함수명' (@Query ('변수 이름') '자료형' '변수 이름') 형태로 나타나 있는데요
@Query 를 통해 위치가 바뀌어도 동적으로 값을 받아올 수 있습니다!
다음으로는 응답 샘플 코드를 보겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | { "result":{ "message":"성공", "code":9200, "requestUrl":"/weather/current/hourly?lon=&village=도곡동&county=강남구&lat=&city=서울&version=1" }, "common":{ "alertYn":"Y", "stormYn":"N" }, "weather":{ "hourly":[ { "grid":{ "latitude":"37.4870600000", "longitude":"127.0460400000", "city":"서울", "county":"강남구", "village":"도곡동" }, "wind":{ "wdir":"266.00", "wspd":"3.20" }, "precipitation":{ "type":"0", "sinceOntime":"0.00" }, "sky":{ "name":"맑음", "code":"SKY_O01" }, "temperature":{ "tc":"6.80", "tmax":"8.10", "tmin":"-0.90" }, "humidity":"31.00", "lightning":"0", "timeRelease":"2013-11-11 14:00:00" } ] } } | cs |
여기서 저희는 필요한 것만 골라서 받아올 수 있습니다!
갓 구글께서는 JSON을 쉽게 파싱할 수 있도록 GSON 라이브러리를 만들어 주셨습니다.
이를 야무지게 사용해 보겠습니다.
public class WeatherRepo {
@SerializedName("result")
Result result;
@SerializedName("weather")
weather weather;
public class Result {
@SerializedName("message") String message;
@SerializedName("code") String code;
public String getMessage() {return message;}
public String getCode() {return code;}
}
public class weather {
public List<hourly> hourly = new ArrayList<>();
public List<hourly> getHourly() {return hourly;}
public class hourly {
@SerializedName("sky") Sky sky;
@SerializedName("precipitation") precipitation precipitation;
@SerializedName("temperature") temperature temperature;
@SerializedName("wind") wind wind;
public class Sky{
@SerializedName("name") String name;
@SerializedName("code") String code;
public String getName() {return name;}
public String getCode() {return code;}
}
public class precipitation{ // 강수 정보
@SerializedName("sinceOntime") String sinceOntime; // 강우
@SerializedName("type") String type; //0 :없음 1:비 2: 비/눈 3: 눈
public String getSinceOntime() {return sinceOntime;}
public String getType() {return type;}
}
public class temperature{
@SerializedName("tc") String tc; // 현재 기온
public String getTc() {return tc;}
}
public class wind{ // 바람
@SerializedName("wdir") String wdir;
@SerializedName("wspd") String wspd;
public String getWdir() {return wdir;}
public String getWspd() {return wspd;}
}
public Sky getSky() {return sky;}
public hourly.precipitation getPrecipitation() {return precipitation;}
public hourly.temperature getTemperature() {return temperature;}
public hourly.wind getWind() {return wind;}
}
}
public Result getResult() {return result;}
public weather getWeather() {return weather;}
public interface WeatherApiInterface {
@Headers({"Accept: application/json"})
@GET("weather/current/hourly")
Call<WeatherRepo> get_Weather_retrofit(@Query("version") int version, @Query("lat") String lat, @Query("lon") String lon);
}
}
위의 응답 데이터 양식과 아래의 코드를 보면
GSON이 쉽고 편하고 아름답게 파싱해 주는 것을 볼 수 있습니다!
여기서 @SerializedName 어노테이션이 포인트인데요
이 어노테이션을 이용하면 wspd(풍속) 을
@SerializedName("wspd") String windSpeed; 처럼 변수 이름을 바꿔 넣을 수도 있습니다.
응답코드에 hourly 뒤를 보시면 JSONArray 형태로 되어 있는데요
이를 위와 같이 클래스로 만들어 ArrayList<hourly> 형태로 만들어준다면 쉽게 파싱이 가능합니다!
이부분을 잘 몰라서 삽질 했던 기억이 나네요...
다음으로는 위에서 만든 Retrofit interface를 구현해보도록 하겠습니다!
저는 날씨 정보를 가져오는 스레드인
WeatherThread 에서 날씨 정보를 받아오겠습니다.
public class WeatherThread extends Thread {
final static String TAG = "WeatherThread";
Context mContext;
WeatherRepo weatherRepo;
Handler handler;
int version = 1;
String lat;
String lon;
public WeatherThread(Handler handler, Context mContext, double lat, double lon) {
this.mContext = mContext;
this.lat = String. valueOf(lat);
this.lon = String .valueOf(lon);
this.handler = handler;
}
@Override
public void run() {
super.run();
Retrofit client = new Retrofit.Builder().baseUrl("http://apis.skplanetx.com/").addConverterFactory(GsonConverterFactory.create()).build();
WeatherRepo.WeatherApiInterface service = client.create(WeatherRepo.WeatherApiInterface.class);
Call<WeatherRepo> call = service.get_Weather_retrofit(version, lat, lon);
call.enqueue(new Callback<WeatherRepo>() {
@Override
public void onResponse(Call<WeatherRepo> call, Response<WeatherRepo> response) {
if(response.isSuccessful()){
weatherRepo = response.body();
Log.d(TAG,"response.raw :"+response.raw());
if(weatherRepo.getResult().getCode().equals("9200")){ // 9200 = 성공
Weather.getInstance().setTemperature(weatherRepo.getWeather().getHourly().get(0).getTemperature().getTc());
Weather.getInstance().setCloud(weatherRepo.getWeather().getHourly().get(0).getSky().getName());
Weather.getInstance().setWind_direction(weatherRepo.getWeather().getHourly().get(0).getWind().getWdir());
Weather.getInstance().setWind_speed(weatherRepo.getWeather().getHourly().get(0).getWind().getWspd());
Weather.getInstance().setIcon(weatherRepo.getWeather().getHourly().get(0).getSky().getCode());
Message msg = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString("weather","weather");
msg.setData(bundle);
handler.sendMessage(msg);
}else{
Log.e(TAG,"요청 실패 :"+weatherRepo.getResult().getCode());
Log.e(TAG,"메시지 :"+weatherRepo.getResult().getMessage());
}
}
}
@Override
public void onFailure(Call<WeatherRepo> call, Throwable t) {
Log.e(TAG,"날씨정보 불러오기 실패 :" + t.getMessage() );
Log.e(TAG,"요청 메시지 :"+call.request());
}
});
}
}
생성자를 통해 위도와 경도를 받아와
service.get_Weather_retrofit(version, lat, lon) 부분에 값을 넣어줍니다.
요청이 성공적으로 수행되면 onResponse로 진입을 하게 되는데 이곳에서 response.isSuccessful() 로 요청이 성공적으로 이루어 지면
WeatherRepo 에 response.body를 입혀줍니다. response.body 에는 위의 응답 샘플 코드와 같은 정보가 들어있어 이를
GSON으로 파싱 할 수 있을 것입니다.
response.raw 함수로 응답으로 온 http raw 데이터를 볼 수 있습니다.
응답코드가 정상인지 확인한 후
weatherRepo.get~~~ 함수들로 값을 받아와 객체에 저장할 수 있습니다!
Retrofit은 제가 사용한 GET 방법 외에도 POST, PUT 등 다양한 Request 방식을 지원합니다.
여러가지 사용법은 추후 공부를 더 하게되면 추가 해 나가도록 하겠습니다!
이상 Retrofit 사용법 글을 마치겠습니다 감사합니다!
'안드로이드' 카테고리의 다른 글
zip exception (com/google/android/gms/internal) 오류 해결법 (1) | 2017.01.17 |
---|---|
안드로이드 - 카카오톡 로그인 연동 part 3 (9) | 2016.01.26 |
안드로이드 - 카카오톡 로그인 연동 part 2 (3) | 2016.01.26 |
안드로이드 - 카카오톡 로그인 연동 part 1 (4) | 2016.01.26 |