はじめに
この記事は、DroidKaigi2017で発表した『いまからはじめるAndroid 6.0対応 〜Android 7.0から8.xを見つめて〜』の補完的な記事になります。
概要
Android 6.0から Apache HTTP Clientが廃止されました。特にGoogleが提供していた通信ライブラリ「Volley」がこの影響をモロに受けてしまっています。
自分が前職で関わっていたアプリもほぼ全てがVolleyを利用していました。結局はOkHttpやRetrofitへの移行によって対応を行ったのですが、(特にOkHttpへの)移行は比較的スムーズに移行が進んだこともあり、改めて「非同期通信を各ライブラリで実装した場合」のサンプルを掲載します。
useLibrary 'org.apache.http.legacy'
について
Apache HTTP Client の削除 | Android 6.0 の変更点 | Android Developers
実は公式から「Apache HTTP Clientをどうしても使いたい場合の応急的な解決策」は用意されています。
とはいえ、あくまでも応急的な解決策に近いものと考えています。公式にいつ削除するとは明言されていないものの、削除しないのであれば最初から除外されるはずがないので、早い段階でApache HTTP Clientを必要としない形への実装に変えるべきだと思います。
ちなみにこの対応を行ったVolleyがGitHubに上がっています。本記事のVolleyサンプルも、こちらのVolleyを利用して実装しています。いずれはこちらもApache HTTP Clientの対応を完了したものになるかもしれないですね。
実装
Clientクラスによるラッパークラスでの実装について
これが正解!とは口が裂けても言えませんが、移行対象としていたアプリの通信処理は、別途通信処理をラップしたClientクラスに対してやりとりを行うようにする設計をしていました。これによってView側では「どうやってModelを取得するか」を意識しない形となっていたため、変更点も最小限にとどまったような気がしています。
本来ならMVPだのMVVMといった「キレイ」な依存関係を作るべきだと思うのですが、いきなり全部を完璧にこなすのは大変だなあと思います。とはいえ、まずはこの程度の「Viewが使うライブラリに依存しない」レベルの分割はやっておいてからOkHttpなどへの移行を進めたほうがスムーズに移行できるのかなと思います。
サンプルコード
今回は自身が移行に対応したアプリの条件を前提としているので
- GET通信
- JSONが返却されるのでGsonを使ってパース
- 主に非同期通信
という前提で記載しています。あくまでも「そんなに実装方法に違いはないよ」というニュアンスだけ受け取るもので、そのまま考えずにマネないようにしてください。
class RequestClient {
private static final String URL = "https://xxxx.com/get/event/";
static final int METHOD_VOLLEY = 0;
static final int METHOD_OKHTTP = 1;
static final int METHOD_RETROFIT = 2;
interface Listener {
void onSuccess(Event event);
void onFailure();
}
private Listener mListener;
private RequestQueue mRequestQueue; // Volley
private OkHttpClient mOkHttpClient; // OkHttp
RequestClient(Context context, Listener listener) {
this.mListener = listener;
this.mRequestQueue = Volley.newRequestQueue(context);
this.mOkHttpClient = new OkHttpClient();
}
/**
* GET通信の実施(取得するURLは固定)
*
* @param method 利用するライブラリの種類
*/
void get(int method) {
if (method == METHOD_VOLLEY) {
getVolley(mListener);
return;
}
if (method == METHOD_OKHTTP) {
getOkHttp(mListener);
return;
}
if (method == METHOD_RETROFIT) {
getRetrofit(mListener);
return;
}
mListener.onFailure();
}
/**
* Volleyによる非同期GET通信
*
* @param listener リスナー
*/
private void getVolley(final Listener listener) {
JsonObjectRequest request
= new JsonObjectRequest(Request.Method.GET, URL, null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Event event = new Gson().fromJson(response.toString(), Event.class);
listener.onSuccess(event);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
listener.onFailure();
}
});
mRequestQueue.add(request);
mRequestQueue.start();
}
/**
* OkHttp3による非同期GET通信
*
* @param listener リスナー
*/
private void getOkHttp(final Listener listener) {
final okhttp3.Request request = new okhttp3.Request.Builder().url(URL).get().build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
listener.onFailure();
}
@Override
public void onResponse(Call call, okhttp3.Response response) throws IOException {
Event event = new Gson().fromJson(response.body().string(), Event.class);
listener.onSuccess(event);
}
});
}
/**
* Retrofit用のインターフェース:本当は別ファイルに定義した方がいいと思います
*/
interface Api {
@GET("get/event/")
retrofit2.Call<Event> api();
}
/**
* Retrofit2による非同期GET通信
*
* @param listener リスナー
*/
private void getRetrofit(final Listener listener) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://xxxx.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
Api api = retrofit.create(Api.class);
api.api().enqueue(new retrofit2.Callback<Event>() {
@Override
public void onResponse(retrofit2.Call<Event> call, retrofit2.Response<Event> response) {
listener.onSuccess(response.body());
}
@Override
public void onFailure(retrofit2.Call<Event> call, Throwable t) {
listener.onFailure();
}
});
}
}
見ての通り、retrofitだけ少し準備部分が独特ですが通信実行時からのコールバックの流れはVolleyとほとんど変わりがありません。処理を一つ移行するときは時間がかかるかもしれませんが、その後はスムーズに進められるんじゃないでしょうか。
ちょっとだけ注意点(OkHttpとRetrofitの関係性について)
RetrofitはOkHttpをベースに作られたライブラリのため、OkHttpとRetrofitでOkHttpのバージョンが異なることがあります(ややこしい)。
だいたい半年程前はOkHttp自体はv3が公開されていたのに対し、Retrofit内のOkHttpはv2を利用していたことがありましたが、現在はv3を利用しています。
こうした「ズレ」もありますので、ライブラリの採択やアップデート対応には十分留意するようにしましょう。
square/retrofit: Type-safe HTTP client for Android and Java by Square, Inc.