複数の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リポジトリからプロジェクトに取り込む必要があります。