[Android] Retrofit2 と RxJava で WEB-API の通信結果(JSON)を受け取る例

  • 15
    いいね
  • 0
    コメント

例として Qiita API v1 を利用して、Qiitaの 新着投稿の一覧 を取得してみます。

必要なライブラリをプロジェクトへ導入

本投稿の執筆時点(2016.11.04)で最新版を導入します。

  • RxJava (ver 1.2.1)
  • RxAndroid (ver 1.2.1)
  • Gradle Retrolambda Plugin (ver 3.3.0)
  • Retrofit (ver 2.1.0)

    『Gradle Retrolambda Plugin』は Retrolambda のラムダ式を利用できるようにするものです(RxJava 利用コードが煩雑になるのを回避する為)。また Retrolambda を導入するにあたり、開発環境(OS X を想定)には Java 8 を導入してください(Oracleのサイトはこちら)。

    その他、付随して必要になる OkHttp、Gson 等も導入します。

    build.gradle
    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:2.2.1'
    +        classpath 'me.tatarka:gradle-retrolambda:3.3.0'
        }
    }
    
    allprojects {
        repositories {
            jcenter()
        }
    }
    
    task clean(type: Delete) {
        delete rootProject.buildDir
    }
    
    app/build.gradle
    apply plugin: 'com.android.application'
    + apply plugin: 'me.tatarka.retrolambda'
    
    android {
        compileSdkVersion 24
        buildToolsVersion "24.0.3"
        defaultConfig {
            applicationId "io.github.hkusu.rxRetrofit"
            minSdkVersion 21
            targetSdkVersion 23
            versionCode 1
            versionName "0.0.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    +    compileOptions {
    +        sourceCompatibility JavaVersion.VERSION_1_8
    +        targetCompatibility JavaVersion.VERSION_1_8
    +    }
    }
    
    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
            exclude group: 'com.android.support', module: 'support-annotations'
        })
        compile 'com.android.support:appcompat-v7:24.2.1'
        compile "com.android.support:support-v4:24.2.1"
        compile "com.android.support:support-annotations:24.2.1"
    +    compile 'io.reactivex:rxjava:1.2.1'
    +    compile 'io.reactivex:rxandroid:1.2.1'
    +    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    +    compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
    +    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
    +    compile 'com.google.code.gson:gson:2.7'
    +    compile 'com.squareup.okhttp3:okhttp:3.4.1'
        testCompile 'junit:junit:4.12'
    }
    

Gson モデルの作成

API のレスポンス(JSON形式)で受け取るデータを Gson のモデルで表現します。全ての項目を定義する必要はなく、受け取りたい項目のみでよいです。

QiitaItem.java
// ...

public class QiitaItem {
    @SerializedName("id")
    public int id;

    @SerializedName("uuid")
    public String uuid;

    @SerializedName("title")
    public String title;

    @SerializedName("url")
    public String url;

    @SerializedName("user")
    public QiitaItemUser user;
}

入れ子の場合(上記でいうとuser)は子のモデルも作成します。

QiitaItemUser.java
// ...

public class QiitaItemUser {
    @SerializedName("id")
    public int id;

    @SerializedName("url_name")
    public String urlName;

    @SerializedName("profile_image_url")
    public String profileImageUrl;
}

API の作成

Retrofit2 で API を定義します。

QiitaApiService.java
// ...

public interface QiitaApiService {
    @GET("items?per_page=10&page=1")
    Observable<List<QiitaItem>> items();

    // 他に API があればここに並べる
}

この例だと item() メソッドで Qiita API の items?per_page=10&page=1 に HTTP の GET メソッドでアクセスし、戻り値は RxJava の Observable 型(中身は先程 Gson モデルで定義した QiitaItem の List)です。

この API サービスのインスタンス化するには次のようにします。API の基準 URL はここで指定します。

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://qiita.com/api/v1/")
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();
qiitaApiService = retrofit.create(QiitaApiService.class);

この API サービスのインスタンス(qiitaApiService)は何度も作成するのは無駄なので、アプリケーション全体で使いまわすようにします。方法は色々ありますが(自分なら Dagger2 を使いますが)、例えば Application クラスに保持する場合は次のようにします。

MainApplication.java
// ...

public class MainApplication extends Application {
    private QiitaApiService qiitaApiService = null;

    @Override
    public void onCreate() {
        super.onCreate();
    }

    public QiitaApiService getQiitaApiService() {
        if (qiitaApiService == null) {
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://qiita.com/api/v1/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .build();
            qiitaApiService = retrofit.create(QiitaApiService.class);
        }
        return  qiitaApiService;
    }
}

もしくは static フィールドと static メソッドでインスンタンスの保持と配信をするような Provider を作成する場合は次のようにします。

Provider.jama
public class Provider {
    private static QiitaApiService qiitaApiService = null;

    public static QiitaApiService provideQiitaApiService() {
        if (qiitaApiService == null) {
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://qiita.com/api/v1/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .build();
            qiitaApiService = retrofit.create(QiitaApiService.class);
        }
        return qiitaApiService;
    }
}

API の利用

例えば Activity の onResume() で API にアクセスし結果をログに出力するコードは次のようになります。

MainActivity.java
// ...

public class MainActivity extends AppCompatActivity {
    private QiitaApiService qiitaApiService;
    private Subscription subscription;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        qiitaApiService = ((MainApplication) getApplication()).getQiitaApiService();
    }

    @Override
    protected void onResume() {
        super.onResume();
        // Qiitaの新着アイテムを取得
        subscription = qiitaApiService.items()
                .subscribeOn(Schedulers.io()) // バックグランドで実行
                .observeOn(AndroidSchedulers.mainThread()) // UIスレッドで購読
                .subscribe(aQiitaItemList -> {
                    // ログにタイトルを出力
                    for (QiitaItem qiitaItem: aQiitaItemList) {
                        Log.d("QiitaItem:", qiitaItem.title);
                    }
                });
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 購読解除
        subscription.unsubscribe();
    }
}

結果は次のとおりです。

スクリーンショット 2016-11-04 22.25.06.png

おわりに

今回のソースコードは GitHub に置きました。必要に応じて参照ください。
https://github.com/hkusu/android-rx-retrofit-example