しかし、XMLやJSONをパースするような単調な処理は出来るだけ無くしたいので、
Spring AndroidとSimple(xmlシリアルフレームワーク)を使用してXMLデータを取得し、
アプリに表示させてみた。
今回はイベント開催支援ツールのATNDのAPIを使用してAndroid系イベントを取得して
イベントタイトルとイベント日時をアプリにリスト表示してみる。
実際に使用するAPI→http://api.atnd.org/events/?keyword=android&format=xml
サンプルプロジェクトのダウンロードリンクは記事の最後。
まず前エントリーを参考にMavenプロジェクトからAndroidプロジェクトを作成。
pom.xmlを追記
<dependency> <groupId>org.simpleframework</groupId> <artifactId>simple-xml</artifactId> <version>2.6.1</version> <exclusions> <exclusion> <artifactId>stax</artifactId> <groupId>stax</groupId> </exclusion> <exclusion> <artifactId>stax-api</artifactId> <groupId>stax</groupId> </exclusion> <exclusion> <artifactId>xpp3</artifactId> <groupId>xpp3</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.android</groupId> <artifactId>spring-android-rest-template</artifactId> <version>1.0.0.M4</version> </dependency> <repositories> <repository> <id>org.springframework.maven.milestone</id> <name>Spring Maven Milestone Repository</name> <url>http://maven.springframework.org/milestone</url> <snapshots><enabled>false</enabled></snapshots> </repository> </repositories>
次にXMLデータをマッピングさせるオブジェクトを作成する。
要素には@Element、属性には@Attributeをつける。
@Element、@Attributeのnameは要素名(属性名)と変数名が同じであれば省略可能。
XMLのすべての要素をオブジェクトにマッピングしない場合は@Rootアノテーションにstrict = false
をつける必要がある。
Event.java
package jp.u1aryz.products.atndsearch; import org.simpleframework.xml.Element; import org.simpleframework.xml.Root; @Root(name = "event", strict = false) public class Event { @Element private String title; @Element(name = "started_at") private String eventDate; public void setTitle(String title) { this.title = title; } public String getTitle() { return title; } public void setEventDate(String eventDate) { this.eventDate = eventDate; } public String getEventDate() { return eventDate; } }
リストの場合は@ElementListアノテーションを使う。
EventList.java
package jp.u1aryz.products.atndsearch; import java.util.List; import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Root; @Root(name = "events", strict = false) public class EventList { @ElementList private List<Event> events; public void setEvents(List<Event> events) { this.events = events; } public List<Event> getEvents() { return events; } }
そしてXMLデータからオブジェクトにマッピングさせる処理を作成する。
HTTP通信は通常、UIスレッドとは別のスレッドで行うため、今回のポイントとなる処理も
doInBackground内に入れる。
GetAndroidEventActivity.java
package jp.u1aryz.products.atndsearch; import java.util.ArrayList; import java.util.List; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; import android.app.ListActivity; import android.app.ProgressDialog; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; public class GetAndroidEventActivity extends ListActivity { private static String TAG = GetAndroidEventActivity.class.getSimpleName(); private ProgressDialog progressDialog; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override protected void onStart() { super.onStart(); // ATND APIの呼び出しを非同期で行う new GetEventTask().execute(); } private void refreshEvents(List<Event> events) { if (events != null) { EventListAdapter adapter = new EventListAdapter(this, events); setListAdapter(adapter); } } public void showProgressDialog() { if (progressDialog == null) { progressDialog = new ProgressDialog(this); progressDialog.setIndeterminate(true); } progressDialog.setMessage("Loading. Please wait..."); progressDialog.show(); } public void dismissProgressDialog() { if (progressDialog != null) { progressDialog.dismiss(); } } private class GetEventTask extends AsyncTask<Void, Void, List<Event>> { @Override protected void onPreExecute() { // プログレスバーを表示 showProgressDialog(); } @Override protected List<Event> doInBackground(Void... params) { try { // Android関連のイベントを検索するURL String url = "http://api.atnd.org/events/?keyword=android&format=xml"; // Acceptヘッダに"application/xml"をセット HttpHeaders requestHeaders = new HttpHeaders(); List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>(); acceptableMediaTypes.add(MediaType.APPLICATION_XML); requestHeaders.setAccept(acceptableMediaTypes); HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders); RestTemplate restTemplate = new RestTemplate(); // HTTPのGETリクエストを実行(マッピングさせるクラスを指定する) ResponseEntity<EventList> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, EventList.class); // イベントリストを取得 EventList eventList = responseEntity.getBody(); return eventList.getEvents(); } catch (Exception e) { Log.e(TAG, e.getMessage(), e); } return null; } @Override protected void onPostExecute(List<Event> result) { // プログレスバーを非表示 dismissProgressDialog(); // 結果を返す refreshEvents(result); } } }
最後にViewに取得したデータをセットするAdapterの作成。
特別な処理はしていないので、通常のAndroidの知識で理解出来ると思う。
EventListAdapter.java
package jp.u1aryz.products.atndsearch; import java.util.List; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; public class EventListAdapter extends ArrayAdapter<Event> { private LayoutInflater mInflater; public EventListAdapter(Context context, List<Event> objects) { super(context, 0, objects); mInflater = LayoutInflater.from(context); } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { convertView = mInflater.inflate(android.R.layout.simple_list_item_2, null); holder = new ViewHolder(); holder.title = (TextView) convertView.findViewById(android.R.id.text1); holder.eventDate = (TextView) convertView.findViewById(android.R.id.text2); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } Event event = getItem(position); holder.title.setText(event.getTitle()); holder.eventDate.setText(event.getEventDate()); return convertView; } } class ViewHolder { TextView title; TextView eventDate; }
<uses-permission android:name="android.permission.INTERNET" />を忘れなければ
下記のようにイベントを取得出来る。
日時のフォーマットが見づらいけど。。。
これで単調なパース処理とおさらば〜
時間があればJSONバージョンもやるかも!?
ダウンロードはこちらから