複数のWeb APIにアクセスする
緯度、経度が取得できましたので、これまで解説してきたWeb APIを使って、天気情報を取得してみましよう。
IDを指定してローダを識別する
Web APIにアクセスする処理は、Activityに次のコードを追加します。なお、コメント中の(数字)は、実行される順序を示しています。
// GPSの緯度経度をパラメータにして、住所を取得するWebAPIを呼び出す
public void getCurrentAddress(Location location) {
Bundle bundle = new Bundle();
// 緯度・経度
bundle.putString("lat", Double.toString(location.getLatitude()));
bundle.putString("lon", Double.toString(location.getLongitude()));
bundle.putString("geo", "http://www.finds.jp/ws/rgeocode.php?");
// IDに0を指定して、LoaderManagerを初期化(1)
getLoaderManager().restartLoader(0, bundle, this);
}
@Override
public Loader<String> onCreateLoader(int id, Bundle bundle) {
HttpAsyncLoader loader = null;
switch ( id ) {
// 緯度経度から都道府県コードを取得する(2)
case 0:
String url = bundle.getString("geo") + "lat=" + bundle.getString("lat") +
"&" + "lon=" + bundle.getString("lon") + "&json";
loader = new HttpAsyncLoader(this, url);
loader.forceLoad();
break;
// 天気予報を取得する(4)
case 1:
loader = new HttpAsyncLoader(this, bundle.getString("url"));
loader.forceLoad();
break;
}
return loader;
}
@Override
public void onLoadFinished(Loader<String> loader, String body) {
if (body == null) return;
ParseJson analyze = null;
switch ( loader.getId() ) {
// 都道府県コードから、該当の天気予報の取得を開始する(3)
case 0:
analyze = new ParseFindsjp();
analyze.loadJson(body);
Bundle bundle = new Bundle();
bundle.putString("url", "http://www.drk7.jp/weather/json/" +
analyze.getContent() + ".js");
// IDに1を指定して、LoaderManagerを初期化
getLoaderManager().restartLoader(1, bundle, this);
break;
// 天気予報情報を、ビューにセットする(5)
case 1:
analyze = new ParseDrk7jpweather();
analyze.loadJson(body);
TextView tv = (TextView)findViewById(R.id.fullscreen_content);
tv.setText( analyze.getContent() );
break;
}
}
restartLoaderメソッドとは
先ほどの位置情報リスナーのonLocationChangedメソッドのなかで呼び出している、getCurrentAddressメソッドは、取得した緯度、経度と、住所を取得するWeb APIのURLをBundleオブジェクトにセットし、LoaderManagerを初期化しています(1)。
なお今回のコードでは、LoaderManagerの初期化に、restartLoaderメソッドを使っています。これは、アプリの起動時だけでなく、ボタン操作で再度Web APIにアクセスさせたいための処置です。
initLoaderメソッドの場合は、もう一度同じIDでinitLoaderメソッドを実行すると、ローダーを再利用しようとします。つまり、実際にはAPIにアクセスせずに、保存されている結果のみを返します。それでは更新処理にはならないので、最初からローダーを破棄して再作成するrestartLoaderメソッドを実行するようにしています。
ローダーを順番に実行する
前々回で解説したように、initLoader(restartLoader)メソッドを実行すると、onCreateLoaderメソッドが呼ばれ(2、4)、その後Web APIへのアクセスが終了したら、onLoadFinishedメソッドが呼ばれます(3、5)。
住所の取得と、天気情報の取得の2つのAPIに対して、この順番のとおりにアクセスする必要がありますので、IDが0のときの最初のonLoadFinishedメソッドのなかで、2回目のローダーを開始しています。
ここのコードでのポイントは、IDを指定してローダーを識別しているところです。onCreateLoader、onLoadFinishedメソッドは、ローダーに対して共通のメソッドなので、IDを異なる値にしておき、住所の取得なのか、天気情報の取得なのかを判定します。
よりアプリらしくする
以上で、基本となる処理はすべて実装できました。ただ、このままではアプリとしては物足りないので、もう少しコードを追加してみます。
ボタンの処理の追加
今回のアプリで使用したFullscreenActivityでは、画面をタッチすると、その下部にボタンが表示されます。このボタンを押したら、再度、Web APIにアクセスして、情報を更新するようにしてみましょう。
ボタンのリスナーを追加して、メインの処理を呼び出すコードを追加します。
// ボタンクリックのイベントリスナーを追加する
findViewById(R.id.dummy_button).setOnClickListener(clickListener);
View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// 初期表示にする
TextView tv = (TextView)findViewById(R.id.fullscreen_content);
tv.setText(R.string.dummy_content);
// 更新処理開始
execStart();
}
};
R.string.dummy_content(文字列自体はstrings.xmlに定義)は、起動時に表示している文字列のIDです。
背景画像の追加
テンプレートでは背景が単色になっています。これもそのままでは寂しいので、画像を表示するようにしてみましょう。背景画像を追加するには、レイアウトファイルで、TextViewの前に、ImageViewを追加します。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<ImageView
android:id="@+id/imageView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/sky_beiz" />
<TextView
android:gravity="top|left"
android:padding="30dp"
android:textSize="20sp"
android:textStyle="bold" />
サンプルとして添付しているプロジェクトでは、背景画像として、フリー素材の空画像(sky_beiz.jp_M30749.jpg)を、resフォルダ直下のdrawable-xhdpiフォルダにコピーしています。そして、ImageViewのsrc属性で、その画像のIDを指定しています。
ImageViewのlayout_width、layout_height属性には、match_parentを指定して、画面いっぱいに表示させています。また、scaleType属性でcenterCropを指定し、画像の縦横比を維持したまま中央部分が表示されるようにします。
天気情報を表示するTextViewでは、文字の余白とフォントサイズを適宜変更しています。
最後に
今回は、位置情報の取得、Web APIアクセスを複数行う処理について解説しました。次回からは、Google Maps Android APIを使った地図アプリを作っていきましょう。
本年の5月に開催された開発者向けイベント「Google I/O 2013」で、Volleyというネットワーク処理のライブラリが発表されました。Volleyを使うと、直接AsyncTaskLoaderを使うよりも、シンプルにネットワーク処理を実装することができます。今後は、このライブラリの使用が推奨されるようになるでしょう。
ただし、現時点ではまだSDKに含まれていませんので、この連載では、おもにAsyncTaskLoaderを使ったコードを解説します。なお、Volleyを使用するには、別途Gitリポジトリからプロジェクトに取り込む必要があります。
