#はじめに
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プロジェクトに導入する。
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クラスを作成します。
※天気予報以外の情報については割愛します。
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"
}
}
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;
}
}
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 インターフェースを作成する
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);
}
##非同期で通信を行う
実際に通信して、結果データを返却するまでの処理は以下のようになります。
画面の表示については今回割愛します。
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);
}
}
#まとめ
非常にシンプルに処理をかけました。今後新規にサーバーとの通信を行うようなアプリでは
採用して見てはいかがでしょうか。