Java
Android
RxAndroid
Dagger2
Retrofit2

Dagger2 + Retrofit2 + RxAndroidで通信してみる

More than 1 year has passed since last update.

為替APIを使ってDagger2 + Retrofit2 + RxAndroidで通信を試してみたいと思います。

基本的には、以前書いたものにDagger2を加えただけになります。
http://qiita.com/MuuKojima/items/01a0738e4c4d1879189c

今回の内容としてはUSDからJPYに変換した為替レートを受け取りTextViewに表示するだけです。
使うAPI: http://fixer.io/ なかなか便利そうですね。

実際のリクエストです。http://api.fixer.io/latest?base=USD&symbols=JPY
下記のように1件JPYのレートが入っています。

今回の例
{
    base: "USD",
    date: "2016-11-09",
    rates: {
    JPY: 103.92
    }
}

それでは、まずrootのbuild.gradleの設定から

build.gradle
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.0'

       // 追加
       classpath 'com.uphyca.gradle:gradle-android-apt-plugin:0.9.4'
    }
}

appのbuild.gradle

build.gradle
apply plugin: 'com.android.application'
// 追加 ↑の下に入れる事
apply plugin: 'android-apt'

dependencies {  

    //////// 追加 ////////

    // RxAndroid
    compile 'io.reactivex:rxjava:1.1.0'
    compile 'io.reactivex:rxandroid:1.1.0'
    // Dagger
    compile 'com.google.dagger:dagger:2.2'
    apt 'com.google.dagger:dagger-compiler:2.2'
    // Retrofit
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
    compile 'com.squareup.retrofit2:converter-gson:2.0.2'
    compile 'com.squareup.retrofit2:retrofit:2.0.2'
    // OkHttp
    compile 'com.squareup.okhttp3:okhttp:3.2.0'
    compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'
    // Gson
    compile 'com.google.code.gson:gson:2.6.2'
}

AndroidManifest.xmlにインターネットパーミッションを1行追加

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kojimation.com.retrofitsample">

    <!-- 追加 -->
    <uses-permission android:name="android.permission.INTERNET" />

</manifest>

今回使う、為替レートを取得するAPIの作成
rxじゃないObservableをimportしないように注意

ExchangeRateApi.java
public interface ExchangeRateApi {
    String URL = "/latest";

    @GET(URL)
    Observable<ExchangeRateResponse> getExchangeRate(@Query("base") String base,
                                                     @Query("symbols") String symbols);
}

AppModuleを作成

AppModule.java
@Module
public class AppModule {

    Application mApplication;

    public AppModule(Application mApplication) {
        this.mApplication = mApplication;
    }

    @Provides
    @Singleton
    Application provideApplication() {
        return mApplication;
    }
}

ApiModuleを作成

ApiModule.java
@Module
public class ApiModule {

    @Provides
    @Singleton
    Gson provideGson() {
        GsonBuilder gsonBuilder = new GsonBuilder();
        return gsonBuilder.create();
    }

    @Provides
    @Singleton
    OkHttpClient provideOkhttpClient() {
        OkHttpClient.Builder client = new OkHttpClient.Builder();
        client.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY));
        return client.build();
    }

    @Provides
    @Singleton
    Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {
        return new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                // ベースのURLの設定
                .baseUrl("http://api.fixer.io")
                .client(okHttpClient)
                .build();
    }

    @Provides
    @Singleton
    public ExchangeRateApi providesExchangeApi(Retrofit retrofit) {
        return retrofit.create(ExchangeRateApi.class);
    }
}

AppComponentを作成

AppComponent.java
@Singleton
@Component(modules = {AppModule.class, ApiModule.class})
public interface AppComponent {
    void inject(MainActivity activity);
}

一旦、実行もしくはrebuildする(DaggerAppComponentが生成される)
Applicationクラスを継承したAppApplicationを作成

Application.java
public class AppApplication extends Application {

    private AppComponent mAppComponent;

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

        mAppComponent = DaggerAppComponent.builder()
                .appModule(new AppModule(this))
                .apiModule(new ApiModule())
                .build();
    }

    public AppComponent getAppComponent() {
        return mAppComponent;
    }
}

Applicationクラスを使うので、AndroidManifest.xmlに android:name=".AppApplication" を一行追記

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kojimation.com.daggerretrofitrxandorid">

    <!-- 追加 -->
    <uses-permission android:name="android.permission.INTERNET" />

    <!-- このタグの中に追加 -->
    <application
        android:name=".AppApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

APIから返って来るレスポンスのオブジェクトを作成

ExchangeRateResponse.java
public class ExchangeRateResponse {
    private String base;
    private String date;
    private CountryCode rates;

    public String getBase() {
        return base;
    }

    public String getDate() {
        return date;
    }

    public CountryCode getRates() {
        return rates;
    }
}
CountryCode.java
public class CountryCode {
    private float JPY;

    public float getJPY() {
        return JPY;
    }
}

MainActivityのxmlにTextViewを1つ追加

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="kojimation.com.retrofitsample.MainActivity">

    <!-- 追加 -->
    <TextView
        android:id="@+id/txt_jpy"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

MainActivityから実際に使ってみる

MainActivity.java
public class MainActivity extends AppCompatActivity {

    @Inject
    ExchangeRateApi mExchangeRateApi;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((AppApplication) getApplication()).getAppComponent().inject(this);

        mExchangeRateApi.getExchangeRate("USD", "JPY")
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<ExchangeRateResponse>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.d("通信 -> ", "失敗" + e.toString());
                    }

                    @Override
                    public void onNext(ExchangeRateResponse exchangeRateResponse) {
                        Log.d("通信 -> ", "成功");
                        TextView textView = (TextView) findViewById(R.id.txt_jpy);
                        textView.setText("JPY: " + String.valueOf(exchangeRateResponse.getRates().getJPY()));
                    }
                });
    }
}

実行結果

スクリーンショット 2016-11-14 午後4.51.49.png

Githubにサンプルを置いておきます
https://github.com/MuuKojima/DaggerRetrofitRxAndroidSample
MVPの構成を適用したものを追記しておきます
http://qiita.com/MuuKojima/items/8843c9451339a8b68f22