LoginSignup
24
26

More than 5 years have passed since last update.

非同期通信をVolleyとOkHttpとRetrofitそれぞれで書いた場合の超簡易サンプル

Last updated at Posted at 2017-03-22

はじめに

この記事は、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を取得するか」を意識しない形となっていたため、変更点も最小限にとどまったような気がしています。

View-Client.png

本来ならMVPだのMVVMといった「キレイ」な依存関係を作るべきだと思うのですが、いきなり全部を完璧にこなすのは大変だなあと思います。とはいえ、まずはこの程度の「Viewが使うライブラリに依存しない」レベルの分割はやっておいてからOkHttpなどへの移行を進めたほうがスムーズに移行できるのかなと思います。

サンプルコード

今回は自身が移行に対応したアプリの条件を前提としているので

  • GET通信
  • JSONが返却されるのでGsonを使ってパース
  • 主に非同期通信

という前提で記載しています。あくまでも「そんなに実装方法に違いはないよ」というニュアンスだけ受け取るもので、そのまま考えずにマネないようにしてください。

RequestClient.java
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.

参考リンク

24
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
26