LoginSignup
86
86

More than 5 years have passed since last update.

OkHTTP + Retrofit + RxAndroid で RESTを試してみました

Last updated at Posted at 2015-11-08

はじめに

AndroidのRESTクライアントのネットワーク処理と非同期処理について、Volley + Gsonの組み合わせでAsyncTask or AsyncLoaderで別スレッドを作って通信して結果を取得してJSONをパースしていたりしていましたが今の流行りはOkHTTP + retorofit + RxAndroidのようなので試してみたいと思います。

本記事のゴール

無料のlivedoor 天気情報APIを使ってデータを受け取る部分までをやりたいと思います。

APIの詳細は以下をご確認ください
http://weather.livedoor.com/weather_hacks/

環境

  • Android studio 1.4
  • OkHTTP:HTTP クライアント用のライブラリ
  • Retrofit:REST クライアント用のライブラリ
  • RxAndroid:リアクティブプログラミングを Android で実装するためのライブラリ
  • Gson:Googleが提供するJSONデータとJavaオブジェクトを相互に変換するためのライブラリ

導入してみよう

ライブラリを Androidプロジェクトに導入する。

Commnad
dependencies {
   compile 'com.squareup.okhttp:okhttp:2.5.0''
    compile 'com.squareup.retrofit:retrofit:1.9.0'
    compile 'io.reactivex:rxandroid:0.24.0'
    compile 'com.google.code.gson:gson:2.2.4'
}

実装

JSONをGETしてくるサンプルを実装したいと思います。

Entityを作成する

天気予報情報を保持するEntityクラスを作成します。
※天気予報以外の情報については割愛します。

天気予報APIの結果で返却されるJSON
http://weather.livedoor.com/forecast/webservice/json/v1?city=200010

{
    "pinpointLocations": [
        {
            "link": "http://weather.livedoor.com/area/forecast/2020100",
            "name": "長野市"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2020700",
            "name": "須坂市"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2021100",
            "name": "中野市"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2021200",
            "name": "大町市"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2021300",
            "name": "飯山市"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2021800",
            "name": "千曲市"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2048100",
            "name": "池田町"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2048200",
            "name": "松川村"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2048500",
            "name": "白馬村"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2048600",
            "name": "小谷村"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2052100",
            "name": "坂城町"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2054100",
            "name": "小布施町"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2054300",
            "name": "高山村"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2056100",
            "name": "山ノ内町"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2056200",
            "name": "木島平村"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2056300",
            "name": "野沢温泉村"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2058300",
            "name": "信濃町"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2058800",
            "name": "小川村"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2059000",
            "name": "飯綱町"
        },
        {
            "link": "http://weather.livedoor.com/area/forecast/2060200",
            "name": "栄村"
        }
    ],
    "link": "http://weather.livedoor.com/area/forecast/200010",
    "forecasts": [
        {
            "dateLabel": "今日",
            "telop": "晴れ",
            "date": "2015-11-06",
            "temperature": {
                "min": {
                    "celsius": "4",
                    "fahrenheit": "39.2"
                },
                "max": {
                    "celsius": "20",
                    "fahrenheit": "68.0"
                }
            },
            "image": {
                "width": 50,
                "url": "http://weather.livedoor.com/img/icon/1.gif",
                "title": "晴れ",
                "height": 31
            }
        },
        {
            "dateLabel": "明日",
            "telop": "曇時々晴",
            "date": "2015-11-07",
            "temperature": {
                "min": null,
                "max": null
            },
            "image": {
                "width": 50,
                "url": "http://weather.livedoor.com/img/icon/9.gif",
                "title": "曇時々晴",
                "height": 31
            }
        }
    ],
    "location": {
        "city": "長野",
        "area": "信越・北陸",
        "prefecture": "長野県"
    },
    "publicTime": "2015-11-05T17:00:00+0900",
    "copyright": {
        "provider": [
            {
                "link": "http://tenki.jp/",
                "name": "日本気象協会"
            }
        ],
        "link": "http://weather.livedoor.com/",
        "title": "(C) LINE Corporation",
        "image": {
            "width": 118,
            "link": "http://weather.livedoor.com/",
            "url": "http://weather.livedoor.com/img/cmn/livedoor.gif",
            "title": "livedoor 天気情報",
            "height": 26
        }
    },
    "title": "長野県 長野 の天気",
    "description": {
        "text": " 日本付近は、広く高気圧に覆われています。\n\n 長野県内は、晴れまたは薄曇りとなっています。\n\n 5日は、高気圧に覆われる見込みです。\n このため、おおむね晴れるでしょう。\n\n 6日は、日中は高気圧に覆われますが、気圧の谷や湿った空気の影響を受\nける見込みです。\n このため、北部では、晴れで夜は曇りとなるでしょう。中部と南部では、\n晴れで朝晩は曇りとなるでしょう。\n\n<天気変化等の留意点>\n 5日18時から6日18時までの24時間に予想される降水量は、多い所\nで、北部で0ミリ、中部で0ミリ、南部で0ミリの見込みです。",
        "publicTime": "2015-11-05T16:39:00+0900"
    }
}
WeatherEntity.java
public class WeatherEntity {

        @Expose
    @SerializedName("pinpointLocations")
    private List<PinpointLocations> pinpointLocations;

    @Expose
    @SerializedName("forecasts")
    private List<Forecasts> forecasts;

    @Expose
    @SerializedName("link")
    private String link;

    public List<Forecasts> getForecasts() {
        return forecasts;
    }

    public void setForecasts(List<Forecasts> forecasts) {
        this.forecasts = forecasts;
    }

    public String getLink() {
        return link;
    }

    public void setLink(String link) {
        this.link = link;
    }

    public List<PinpointLocations> getPinpointLocations() {
        return pinpointLocations;
    }

    public void setPinpointLocations(List<PinpointLocations> pinpointLocations) {
        this.pinpointLocations = pinpointLocations;
    }
}
PinpointLocations.java
public class PinpointLocations{

    @Expose
    @SerializedName("link")
    private String link;

    @Expose
    @SerializedName("name")
    private String name;

    public String getLink() {
        return link;
    }

    public void setLink(String link) {
        this.link = link;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

REST インターフェースを作成する

WeatherApi.java
package com.example.kazuhiro.restsample.api;

import com.example.kazuhiro.restsample.entity.WeatherEntity;
import retrofit.http.GET;
import retrofit.http.Query;

import rx.Observable;

/**
 * Created by kazuhiro on 15/11/08.
 */
public interface WeatherApi {

    @GET("/forecast/webservice/json/v1")
    public Observable<WeatherEntity> getWeather(@Query("city") final String city);
}

非同期で通信を行う

実際に通信して、結果データを返却するまでの処理は以下のようになります。
画面の表示については今回割愛します。

MainActivity.java
package com.example.kazuhiro.restsample.activity;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import com.example.kazuhiro.restsample.api.WeatherApi;
import com.example.kazuhiro.restsample.entity.WeatherEntity;
import com.example.kazuhiro.restsample.R;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.internal.bind.DateTypeAdapter;

import java.util.Date;

import retrofit.RestAdapter;
import retrofit.android.AndroidLog;
import retrofit.converter.GsonConverter;
import rx.Observer;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

public class MainActivity extends AppCompatActivity {

    private static final String END_POINT = "http://weather.livedoor.com";

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


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


        Gson gson = new GsonBuilder()
                .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
                .registerTypeAdapter(Date.class, new DateTypeAdapter())
                .create();

        // RestAdapterを作成する
        RestAdapter adapter = new RestAdapter.Builder()
                .setEndpoint(END_POINT)
                .setConverter(new GsonConverter(gson))
                .setLogLevel(RestAdapter.LogLevel.FULL)
                .setLog(new AndroidLog("=NETWORK="))
                .build();

        // 天気予報情報を取得する
        //http://weather.livedoor.com/area/forecast/200010
        WeatherApi api =  adapter.create(WeatherApi.class);

        Observer observer = new Observer<WeatherEntity>() {
            @Override
            public void onCompleted() {
                Log.d(TAG, "onCompleted()");
                //必要な情報を取り出して画面に表示してください。
            }

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

            @Override
            public void onNext(WeatherEntity weather) {
                Log.d(TAG, "onNext()");
            }
        };

        api.getWeather("200010")
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);
    }
}

まとめ

非常にシンプルに処理をかけました。今後新規にサーバーとの通信を行うようなアプリでは
採用して見てはいかがでしょうか。

86
86
1

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
86
86