AndroidでAPIとやり取りするライブラリとして、Square社のRetrofitがあります。
こんな感じでとても簡潔に処理が記述できます。
MainApplication.API.getUsers(new Callback<List<User>>() {
@Override
public void failure(RetrofitError e) {
//
}
@Override
public void success(List<User> users, Response response) {
//
}
});
メリットをまとめるとこんな感じです。
- Callbackクラスのインターフェースメソッドがわかりやすくていい感じ。
- URLを各処理の中ではなく別のクラスにまとめて書いておくことができて見通しがいい。
- Gsonでのparseも初期化処理で記述しておけば各処理の中で書かなくていい。
- RestAdapterというクラスを使うことでDIしやすくなる。
- モック用のライブラリも梱包されておりテストも書きやすい。
便利なんですが、実際に使う場合にアレどうやったらいいの?ってことがあったのでまとめておこうと思います。
#1. Gsonなどでconvertする前に何か処理をしたい
初期化時に、setConverter
で独自のCoverterクラスをセットします。ちょっと汚いですが。。
public static final ApiService API = new RestAdapter.Builder()
.setEndpoint("")
.setConverter(new CustomGsonConverter())
.build()
.create(ApiService.class);
public class CustomGsonConverter extends GsonConverter {
private Gson gson;
public CustomGsonConverter() {
this(new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create());
}
public ApiGsonConverter(Gson gson) {
super(gson);
this.gson = gson;
}
@Override
public Object fromBody(TypedInput body, Type type) throws ConversionException {
String charset = "UTF-8";
if (body.mimeType() != null) {
charset = MimeUtil.parseCharset(body.mimeType());
}
InputStreamReader isr = null;
try {
ByteArrayOutputStream baos = inputStreamToOutputStream(body.in());
// ここで何かする
isr = new InputStreamReader(new ByteArrayInputStream(baos.toByteArray()), charset);
return gson.fromJson(isr, type);
} catch (IOException e) {
throw new ConversionException(e);
} catch (JsonParseException e) {
throw new ConversionException(e);
} finally {
if (isr != null) {
try {
isr.close();
} catch (IOException ignored) {
}
}
}
}
#2. 通信時にsession_store_keyを仕込みたい
初期化時に、setRequestInterceptor
で独自のInterceptorクラスをセットします。
public static final ApiService API = new RestAdapter.Builder()
.setEndpoint("")
.setRequestInterceptor(new CustomRequestInterceptor())
.build()
.create(ApiService.class);
public class CustomRequestInterceptor implements RequestInterceptor {
private static final String HEADER_COOKIE = "Cookie";
private static final String EQ = "=";
@Override
public void intercept(RequestInterceptor.RequestFacade request) {
request.addHeader(HEADER_COOKIE, Constants.SESSION_STORE_KEY + EQ + "sessionId");
}
}
#3. 通信エラーが起きた時に共通処理をしたい
初期化時に、setErrorHandler
で独自のErrorHandlerクラスをセットします。
public static final ApiService API = new RestAdapter.Builder()
.setEndpoint("")
.setErrorHandler(new CustomErrorHandler())
.build()
.create(ApiService.class);
public class CustomErrorHandler implements ErrorHandler {
@Override
public Throwable handleError(RetrofitError cause) {
try {
Response response = cause.getResponse();
// ここで何かする
} catch (Exception e) {
//
}
return cause;
}
}
#4. 通信時間を計測したい
初期化時に、setProfiler
で独自のProfilerクラスをセットします。
public static final ApiService API = new RestAdapter.Builder()
.setEndpoint("")
.setProfiler(new CustomProfiler())
.build()
.create(ApiService.class);
public class CustomProfiler implements Profiler {
@Override
public Object beforeCall() {
// afterCallに渡したいデータがあればここで返す
return null;
}
@Override
public void afterCall(RequestInformation requestInfo, long elapsedTime,
int statusCode, Object beforeCallData) {
try {
// ここで何かする。beforeCallDataには、beforeCall()で返されたObjectが入る
} catch (Exception e) {
//
}
}
}