ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

OkHttp3 + Retrofit2 + gson + RxJava + RxLifecycle + retrolambda を使って簡単にAPIを叩く

こんにちは。スマートフォンアプリエンジニアのまさです。
最近Androidの開発をすることになったために、同僚に助けて頂きながら勉強しました。 非同期、安全に、簡単にAPIを叩くために、ライブラリを使って
https://httpbin.org/get
を叩き、jsonデータを取得する方法をご紹介します。

まずは各種ライブラリを使えるようにするために

build.gradle

buildscript {
    dependencies {
        classpath 'me.tatarka:gradle-retrolambda:3.3.1'  // 追加
    }
}

app/build.gradle

apply plugin: 'me.tatarka.retrolambda'  // 追加

android {
  ...
  
   // 追加
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}

dependencies {

    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:25.3.1'
    testCompile 'junit:junit:4.12'

    compile 'io.reactivex:rxandroid:1.2.1'
    compile 'io.reactivex:rxjava:1.2.1'
    compile 'com.trello:rxlifecycle:1.0'
    compile 'com.trello:rxlifecycle-components:1.0'

    compile 'com.squareup.okhttp3:okhttp:3.5.0'

    compile 'com.google.code.gson:gson:2.8.0'

    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.0.2'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'

    compile 'io.reactivex:rxandroid:1.2.1'
    compile 'io.reactivex:rxjava:1.2.1'

    retrolambdaConfig 'net.orfjackal.retrolambda:retrolambda:2.3.0'
}

のように編集して、Sync Now します。 これで、今回使うライブラリを使えるようになります。

それでは適当にActivityを作って実装してみます。

package com.unifa_e.studyrx;

import android.os.Bundle;
import android.util.Log;

import com.google.gson.annotations.SerializedName;
import com.trello.rxlifecycle.components.support.RxAppCompatActivity;

import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;
import rx.Observable;
import rx.Observer;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;


public class MainActivity extends RxAppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();

    private static final String accessServer = "https://httpbin.org/";
    private OkHttpClient mClient = new OkHttpClient();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        access();
    }

    private void access() {
        requestGet()
                .compose(bindToLifecycle())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Res>() {
                    @Override
                    public void onCompleted() {
                        Log.d(TAG, "onCompleted");
                    }

                    @Override
                    public void onError(Throwable throwable) {
                        Log.e(TAG, "Error : " + throwable.toString());
                    }

                    @Override
                    public void onNext(Res res) {
                        Log.d(TAG, res.toString());
                    }
                });
    }

    private Observable<Res> requestGet() {
        Retrofit retrofit =
                new Retrofit.Builder()
                        .baseUrl(accessServer)
                        .addConverterFactory(GsonConverterFactory.create())
                        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                        .client(mClient)
                        .build();

        return retrofit.create(SampleApi.class).get();
    }
}

class Res {
    String url;
    String origin;
    Headers headers;

    @Override
    public String toString() {
        return "Res{" +
                "url='" + url + '\'' +
                ", origin='" + origin + '\'' +
                ", headers=" + headers +
                '}';
    }
}

class Headers {
    @SerializedName("Host")
    String host;
    @SerializedName("Connection")
    String connection;

    @Override
    public String toString() {
        return "Headers{" +
                "host='" + host + '\'' +
                ", connection='" + connection + '\'' +
                '}';
    }
}

interface SampleApi {
    @GET("/get")
    Observable<Res> get();
}

※今回は備忘録的にご紹介のため、1ファイル内にシンプルに実装しており、アクセッサやファイルを分けるなどの処理を行なっておりません。

これで実行いただくと、https://httpbin.org/get APIをrequestし、responseのjsonデータをパースしてResクラスへデータを入れ込み、ログを表示します。

簡単な説明

まずは responseに帰ってくるjsonをクラスへデータを入れ込むためのクラスである、 Resクラスと、Headersクラスを作成します。
@SerializedName をつけることで、サーバサイドとメンバ変数名が違う場合には、紐付けを行うことができます。
※今回はサンプルなので、すべてのプロパティを実装していません。

getResメソッドの.addConverterFactory(GsonConverterFactory.create()) をつけることでJSONパーサを行ないます。
Rxをつかい、Observableを返すよう実装しています。

onCreateからAPIを叩くObservableSubScribeして実行します。

AppCompatActivity ではなく、RxAppCompatActivity を継承することで、 RxLifecycle.compose(bindToLifecycle()) を処理チェーンに入れるだけで、利用できます。
いちいちライフサイクルを気にせずにRxを使えるので、すでに存在しないActivityのUIにアクセスするというようなことがなくなって、安全で簡単ですね。

最後に onNextに渡ってきたResクラスを表示させています。

如何でしたでしょうか。最初はとっつきにくかったですが、Rxを使うと見た目もよくなりますし、非同期処理の敷居が下がってとてもいいと思いました。