Android 앱 개발을 하면서 서버와 통신을 위해 네트워크 기능을 쓸 경우가 대다수이다.
기존 네트워크 기능을 위해 HttpURLConnection과 HttpClient (OS 6.0 부터 삭제) 등이 쓰여왔고, OS 3.0 (API 11) 이후에
NetworkOnMainThreadException 를 피하고자 Thread, AsyncTask 등을 사용하기도 했다.
그 후 여러 편의성을 제공하는 통신 라이브러리 들이 등작하였다. OkHttp, Volley (설명), Retrofit ... (라이브러리 비교)
그 중에서 최근까지 많이 쓰이고 있는 Retrofit에 대해서 초간단 맛만 보기로 하자.
0. 준비물 : API, Android Studio, 잠시나마 집중하겠다는 마음가짐.
1. API
직접 준비하기 어려울 경우 공개되어 있는 고마운 API들을 찾아서 사용해보자.
예를 들면 빗썸 OPEN API 같은...
연습을 위해 https://api.bithumb.com/public/ticker/{currency}를 사용해보자.
2. build.gradle 설정
dependencies에 retrofit 최신버전을 추가한다. (Gson 사용을 위해 Gson 관련 추가한다.)
dependencies {
compile 'com.google.code.gson:gson:2.8.2' // Gson 사용시
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0' // Gson 처리시
compile 'com.squareup.retrofit2:converter-scalars:2.3.0' // String 처리시
...
}
3. Data 클래스
결과 JSON에 맞춰 Data 클래스를 생성하자. (Json to Java Object 서비스)
public class BithumbTickerData {
@SerializedName("opening_price")
public String openingPrice;
@SerializedName("closing_price")
public String closingPrice;
@SerializedName("min_price")
public String minPrice;
@SerializedName("max_price")
public String maxPrice;
@SerializedName("average_price")
public String averagePrice;
@SerializedName("units_traded")
public String unitsTraded;
@SerializedName("volume_1day")
public String volume1day;
@SerializedName("volume_7day")
public String volume7day;
@SerializedName("buy_price")
public String buyPrice;
@SerializedName("sell_price")
public String sellPrice;
@SerializedName("date")
public long date;
}
public class BithumbTicker {
@SerializedName("status")
public String status;
@SerializedName("data")
public BithumbTickerData data;
}
4. interface 생성
API Method 방식 및 Path에 대해서 정의하자.
public interface OpenApiService {
@GET("public/ticker/{path}")
Call tickerInfo(@Path("path") String path);
}
5.1. Retrofit 초기화
Retrofit 생성 후 사용할 interface를 통해 서비스를 만들자. (Response를 String 형태로 받고 싶다면 ScalarsConverterFactory 사용)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.bithumb.com/")
.addConverterFactory(GsonConverterFactory.create()) // Gson 처리시
//.addConverterFactory(ScalarsConverterFactory.create()) // String 등 처리시
.build();
OpenApiService openApiService = retrofit.create(OpenApiService.class);
5.2. Call 생성
만들어 둔 interface를 호출하는 Call을 생성하자.
Call tickerInfo = openApiService.tickerInfo("BTC");
5.3. Callback 정의
enqueue() 를 통해 Callback에 대해서 정의하자.
tickerInfo.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
Toast.makeText(TestMainActivity.this, response.body().toString(), Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call call, Throwable t) {
Toast.makeText(TestMainActivity.this, t.toString(), Toast.LENGTH_SHORT).show();
}
});
이상으로 간단하게 Retrofit 시식을 마칠까 한다.
Retrofit 로그 보는 법과 Proguard 설정에 대해서 추가한다.
6. 로그 보는 법
build.gradle에 아래와 같이 추가한다.
dependencies {
compile 'com.squareup.okhttp3:logging-interceptor:3.9.1'
...
}
그리고 Retrofit 초기화 하는 부분에 아래와 같이 추가한다.
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Retrofit.Builder retrofitBuilder = new Retrofit.Builder().baseUrl(url);
if(BuildConfig.DEBUG) {
retrofitBuilder.client(client);
}
if(!isString) {
retrofitBuilder.addConverterFactory(GsonConverterFactory.create());
} else {
retrofitBuilder.addConverterFactory(ScalarsConverterFactory.create());
}
Retrofit retrofit = retrofitBuilder.build();
기존과 비교했을 때 OkhttpClient 라는 놈을 Retrofit Builder에 추가하는 모습이 보인다.
개인적으로 디버그 모드일때만 로그를 보기 위해 BuildConfig.DEBUG 로 분기 처리를 하였다.
그리고 로그 수준은 아래와 같다.
public final class HttpLoggingInterceptor implements Interceptor {
...
public enum Level {
/** No logs. */
NONE,
/**
* Logs request and response lines.
*
* Example:
*
{@code
* --> POST /greeting http/1.1 (3-byte body)
*
* <-- 200 OK (22ms, 6-byte body)
* }
*/
BASIC,
/**
* Logs request and response lines and their respective headers.
*
* Example:
*
{@code
* --> POST /greeting http/1.1
* Host: example.com
* Content-Type: plain/text
* Content-Length: 3
* --> END POST
*
* <-- 200 OK (22ms)
* Content-Type: plain/text
* Content-Length: 6
* <-- END HTTP
* }
*/
HEADERS,
/**
* Logs request and response lines and their respective headers and bodies (if present).
*
* Example:
*
{@code
* --> POST /greeting http/1.1
* Host: example.com
* Content-Type: plain/text
* Content-Length: 3
*
* Hi?
* --> END POST
*
* <-- 200 OK (22ms)
* Content-Type: plain/text
* Content-Length: 6
*
* Hello!
* <-- END HTTP
* }
*/
BODY
}
위 소스를 보면 로그 레벨은 NONE, BASIC, HEADERS, BODY 로 이루어져 있다. 필요에 따라 설정하면 된다.
- NONE : No logs.
- BASIC : Logs request and response lines.
- HEADERS : Logs request and response lines and their respective headers.
- BODY : Logs request and response lines and their respective headers and bodies (if present).
위와 같이 하였을 때 로그는 아래와 같이 떨어진다.
12-26 17:53:03.411 15500-15624/com.test.testblabla D/OkHttp: --> GET https://api.bithumb.com/public/ticker/BTC
12-26 17:53:03.411 15500-15624/com.test.testblabla D/OkHttp: --> END GET
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: <-- 200 https://api.bithumb.com/public/ticker/BTC (693ms)
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: date: Tue, 26 Dec 2017 08:53:04 GMT
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: content-type: application/json
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: set-cookie: __cfduid=dd24fcf80c27cf456c60e275644e40a0e1514278384; expires=Wed, 26-Dec-18 08:53:04 GMT; path=/; domain=.bithumb.com; HttpOnly
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: access-control-allow-origin: *
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: access-control-allow-methods: *
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: access-control-allow-headers: *
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: set-cookie: ci_session=a%3A5%3A%7Bs%3A10%3A%22session_id%22%3Bs%3A32%3A%22cf7e414ece7af81b8a35a0cdcaccd317%22%3Bs%3A10%3A%22ip_address%22%3Bs%3A12%3A%221.227.62.114%22%3Bs%3A10%3A%22user_agent%22%3Bs%3A12%3A%22okhttp%2F3.9.1%22%3Bs%3A13%3A%22last_activity%22%3Bi%3A1514278384%3Bs%3A9%3A%22user_data%22%3Bs%3A0%3A%22%22%3B%7D4ca3239efcb6f4f81c5c8703401ade3bbef4e9fd; expires=Tue, 26-Dec-2017 10:53:04 GMT; Max-Age=7200; path=/
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: server: cloudflare-nginx
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: cf-ray: 3d32cec0fef194b7-NRT
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: {"status":"0000","data":{"opening_price":"19157000","closing_price":"20632000","min_price":"18853000","max_price":"21400000","average_price":"19977707.8742","units_traded":"26050.76859352","volume_1day":"26050.76859352","volume_7day":"176662.05473862","buy_price":"20620000","sell_price":"20623000","date":"1514278384536"}}
12-26 17:53:04.101 15500-15624/com.test.testblabla D/OkHttp: <-- END HTTP (323-byte body)
참조링크1 : https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor
참조링크2 : https://stackoverflow.com/questions/32514410/logging-with-retrofit-2
7. Progaurd 설정
앱을 실제 signed release apk 만들시 Progaurd 사용하는데, 이때 Retrofit 사용시 아래와 같이 proguard.pro 파일에 추가해준다.
# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions
Retrofit 로그에서 문제가 될시 아래도 추가해 보자.
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
참조링크1 : http://square.github.io/retrofit/
참조링크2 : https://github.com/square/okhttp