Androidの開発をしたことがある人なら、Netflixが開発したReactive ExtensionsのJava実装であるRxJavaについて聞いたことがあるかもしれません。引用すると、Reactive Extensionsは、非同期およびイベントベースのプログラミングのために、observableコレクションとLINQスタイルのクエリを組み合わせたサードパーティライブラリです。
必要なライブラリファイルを追加することから始めます。Mavenを使用している場合は、以下の依存関係をpom.xmlに追加するだけです:
<dependency>
<groupId>com.squareup.retrofit</groupId>
<artifactId>retrofit</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>com.netflix.rxjava</groupId>
<artifactId>rxjava-android</artifactId>
<version>0.14.6</version>
</dependency>
この記事では、OpenWeatherMap API をデモ例として使用します。 OpenWeatherMapフリーの気象データAPIで、設定や利用が非常に簡単です。呼び出す際には、位置情報をパラメータとして渡すだけでよく、具体的な効果についてはこの例を参照してください。デフォルトではJSON形式でデータを転送します。精度と温度の単位も設定可能です。詳細はこちらご覧ください。
通常、APIの呼び出しを実装するには、以下の手順が必要です:
- 必要なモデルクラスを作成します。
- エラー処理を伴うリクエスト・レスポンス管理を実装するネットワーク層のコード。
- リクエスト・コールを実装するためにバックグラウンド・スレッドが使用され、UIスレッドでレスポンス・メッセージを表示するためにコールバック関数が使用されます。
モデルクラスの作成
*** 同様のjsonschema2pojoJSON-POJO 生成ツールに頼ることができます:
public class WeatherData {
public Coordinates coord;
public Local sys;
public List<Weather> weathers;
public String base;
public Main main;
public Wind wind;
public Rain rain;
public Cloud clouds;
public long id;
public long dt;
public String name;
public int cod;
public static class Coordinates {
public double lat;
public double lon;
}
public static class Local {
public String country;
public long sunrise;
public long sunset;
}
public static class Weather {
public int id;
public String main;
public String description;
public String icon;
}
public static class Main {
public double temp;
public double pressure;
public double humidity;
public double temp_min;
public double temp_max;
public double sea_level;
public double grnd_level;
}
public static class Wind {
public double speed;
public double deg;
}
public static class Rain {
public int threehourforecast;
}
public static class Cloud {
public int all;
}
}
レトロフィットによるネットワーク・コールの実施
ネットワークコールの実装の2番目のステップは、通常、多くの定型的なコードを記述する必要がありますが、あなたがそれを達成するためにSquareのRetrofit使用すると、コードの量を大幅に削減します。インターフェースクラスを作成し、RestAdapter.Builderを使ってライン上にクライアントを作成するだけです。 Retrofitは、JSONのシリアライズとデシリアライズを完了するためにも使えます。
private interface ApiManagerService {
@GET("/weather")
WeatherData getWeather(@Query("q") String place, @Query("units") String units);
}
具体的な呼び出しの例を見てください。このコードはまだ比較的簡単に理解できます:
//...
final RestAdapter restAdapter = new RestAdapter.Builder()
.setServer("http://..org/data/.5")
.build();
final ApiManagerService apiManager = restAdapter.create(ApiManagerService.class);
final WeatherData weatherData = apiManager.getWeather("Budapest,hu", "metric");
//...
コールプロセス全体を実装するのに必要なコードはほとんどありません。
RxJavaによるレスポンシブプログラミング
次はステップ3、RxJavaの部分です!この例では、非同期リクエストコールを実装するためにRxJavaを使用します。以下のRxJavaの紹介はNetflixのGithubナレッジベースから引用しています:
RxJavaはJava仮想マシン上に実装されたレスポンシブ拡張ライブラリで、観測可能なシーケンス実装とイベントベースのプログラミングに基づく非同期コールを提供します。
Observerパターンを拡張してデータ、イベントシーケンスをサポートし、基礎となるスレッド処理、同期、スレッド安全性、並行データ構造、ノンブロッキングI/O処理を気にすることなくシーケンスをマージすることができます。
Java5以降をサポートし、Groovy、Clojure、Scalaなど他のJVMベースの言語も多数サポートしています。
すでにRxJavaの知識があることを前提としています。そうでない場合は、まずこちらNetflixのGithub Wikiの最初の数ページをチェックすることを強くお勧めします。
この***の例では、観測可能なオブジェクトを生成し、複数の同時呼び出しを行うAPIマネージャが実装されます。
まず、先ほど作成したインターフェイス・クラスをこのクラスに置き換える必要があります:
public class ApiManager {
private interface ApiManagerService {
@GET("/weather")
WeatherData getWeather(@Query("q") String place, @Query("units") String units);
}
private static final RestAdapter restAdapter = new RestAdapter.Builder()
.setServer("http://..org/data/.5")
.build();
private static final ApiManagerService apiManager = restAdapter.create(ApiManagerService.class);
public static Observable<WeatherData> getWeatherData(final String city) {
return Observable.create(new Observable.OnSubscribeFunc<WeatherData>() {
@Override
public Subscription onSubscribe(Observer<? super WeatherData> observer) {
try {
observer.onNext(apiManager.getWeather(city, "metric"));
observer.onCompleted();
} catch (Exception e) {
observer.onError(e);
}
return Subscriptions.empty();
}
}).subscribeOn(Schedulers.threadPoolForIO());
}
}
getWeatherData()メソッドを見てみましょう。Observable.create()を呼び出し、Observable.OnSubscribeFuncの実装を渡してObservableオブジェクトを取得し、それを返すメソッドで、Observableがサブスクライブされると動作を開始します。OnSubscribeFuncの実装でObservableオブジェクトを取得し、それを返すメソッドで、Observableオブジェクトがサブスクライブされると動作を開始し、Observableの各処理の結果がonNext()メソッドのパラメータとして渡されます。ここではネットワークリクエストの同時呼び出しを実装しようとしているだけなので、それぞれのObservableオブジェクトがリクエストを1回呼び出すだけでよいのです。Code*** は onComplete() メソッドを呼び出します。subscribeOn()メソッドは、アプリケーションがどのスレッドを選択するかを決定するため、ここでは重要です。Schedulers.threadPoolForIO()がここで呼び出されます。このスレッドは、IOとネットワークパフォーマンスに関連するタスクを最適化するために使用されます。
*** 最初のステップは、このAPIコールを実装することです。以下のコードでは、それぞれ異なるコールパラメータを使用して同じ url を非同期にコールする、同時 Web リクエストを実装しています:
Observable.from(cities)
.mapMany(new Func1<String, Observable<WeatherData>>() {
@Override
public Observable<WeatherData> call(String s) {
return ApiManager.getWeatherData(s);
}
})
.subscribeOn(Schedulers.threadPoolForIO())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<WeatherData>() {
@Override
public void call(WeatherData weatherData) {
// do your work
}
});
Observable.from()メソッドは都市名の配列をobservableオブジェクトに変換し、配列内の文字列を異なるスレッドに提供します。mapMany()メソッドは、前者によって提供された各文字列をobservableオブジェクト()に変換します。ここでの変換はApiManager.getWeatherData()を呼び出すことで行われます。
ここではまだI/Oスレッドプールに登録されています。Androidでは、結果をUIに表示する必要がある場合、データをUIスレッドにポストして処理する必要があります。Androidでは、UIを作成した元のスレッドだけがUIを操作できることがわかっているからです。ここでは、observeOn()メソッドでAndroidSchedulers.mainThread()を呼び出すだけです。subscribe()メソッドの呼び出しがobservableオブジェクトのトリガーとなり、observableオブジェクトが発行した結果をここで処理できます。
この例はRxJavaの威力を示しています。Rxがなければ、リクエストを呼び出すためにN個のスレッドを作成し、その結果を非同期でUIスレッドに渡す必要があります。Rxを使えば、ほとんどコードを書かずに、Rxのパワーを使ってobservableオブジェクトを生成、結合、フィルタリング、変換することができます。
RxJavaは、Androidアプリを開発する際に並行処理を行うための強力なツールとして使用できます。使いこなすにはまだ時間がかかりますが、一度使いこなせば、ナイフを研ぐことが大いに役立ちます。Responsive Extensionsライブラリは素晴らしいアイデアで、Androidアプリ開発に使うのは数週間前から良いアイデアになっています。知れば知るほど好きになるはずです。
他の情報も必要ですか?RxJavaがどのようにエラー処理を行うかについてはご覧ください。





