Android アプリでよくあるパターンとしては Restful な Web API を呼んで、リストや詳細を表示などが挙げられる。こんなとき、JSONで通信しているのであれば、リクエストのパラメータを作り、レスポンスを解析するというコードを書く必要がある。これが例外処理やらnullチェックやらで何かと面倒。そう感じることが多かった。 最近、gsonとの出会いがあった。なるほど、これを使えばJSONをパースせずともGetter, Setter を持つモデルクラスを作ればそこに詰め込んでくれる優れものだ。だがもっとシンプルにできないだろうか。。
Gson と Generics の相性
Generics は型に縛られず共通処理を書けるようになるテクニックだ。これを使えば以下のようなシンプルなREST クライアントが作成できる。
色々書いて気づいたが、下記コードを見るだけだととてもわかりにくい。この部分だけ切り出したりできないか検討します。。
public class RestApi { public static <T> void index(String url, final Class<T[]> clazz, final ApiCallbackBase.ApiCallback<T[]> callback) { ApiRequest.get(url, getListHandler(clazz, callback)); } private static <T> ApiResponseHandler getListHandler(final Class<T[]> clazz, final ApiCallbackBase.ApiCallback<T[]> callback) { final Context context = ApplicationController.getInstance().getApplicationContext(); return new ApiResponseHandler() { @Override public void onSuccess(JSONObject jsonObject) { try { Gson gson = new GsonBuilder() .setDateFormat(context.getString(R.string.date_parse_in)).create(); LogUtil.d(jsonObject.getJSONArray("item").toString()); T[] dtoList = gson.fromJson(jsonObject.getJSONArray("item").toString(), clazz); if (callback != null) { callback.onSuccess(dtoList); } } catch (JSONException e) { onFailure(new ApiException(e.getMessage(), ApiException.JSON_PARSE_ERROR)); } } @Override public void onFailure(ApiException e) { LogUtil.e("Index Failed.."); LogUtil.e("msg:" + e.getMessage() + ", status: " + e.getStatusCode()); if (callback != null) { callback.onFailure(e.getMessage(), e.getStatusCode()); } } }; } }
ApiRequest
で Volley のhttp 通信を行なう。
public class ApiRequest { public static void get(String url, final ApiResponseHandler handler) { try { request(Request.Method.GET, url, null, handler); } catch (JSONException e) { handler.onFailure(new ApiException(e.getMessage(), ApiException.JSON_PARSE_ERROR)); } } private static void request(final int method, final String url, final JSONObject params, final ApiResponseHandler handler) throws JSONException { RequestDto reqDto = new RequestDto(method, url, params); reqDto.setAccessToken(); JsonObjectRequest req = new JsonObjectRequest(reqDto.method, reqDto.url, reqDto.params, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { handleSuccessResponse(response, handler); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError e) { LogUtil.e("Error: " + e.getMessage()); e.printStackTrace(); int status = ApiException.UNKNOWN_ERROR; if (e.networkResponse != null) { status = e.networkResponse.statusCode; } if (status == 401) { if (params != null && params.has(TokenParamDto.GRANT_REFRESH_TOKEN)) { SignupActivity.redirectToSignup(); } else { tokenRefresh(method, url, params, handler); } return; } try { String responseBody = new String(e.networkResponse.data, "utf-8"); JSONObject jsonObject = new JSONObject(responseBody); LogUtil.e(jsonObject); } catch (Exception e2) { } handler.onFailure(new ApiException(e.getMessage(), status)); } } ); ApplicationController.getInstance().addToRequestQueue(req); }
抜粋ではあるが、OAuthのHttpクライアントとしてリフレッシュトークン、アクセストークンのやりとりを実装するには自前でやるのが一番早い。これらを必要としないシンプルなREST Apiであれば、Retrofit などのOSSを使うことも検討できるだろう。ただ、中身がVolleyじゃなくなるのでそこら辺、自分としては気持ち悪いところ。そこまでこだわりなければ全然使っていいと思う。