はじめに
今回東京メトロオープンデータ活用コンテストで前回下記記事で紹介した、Androidアプリがgoodデザイン賞を受賞しました!!ありがとうございます!
海外で人気のフレームワーク”libGDX”を使って、Androidでアニメーション作ってみた
私は上記で紹介しているTOPのアニメーション部分を担当しましたが、全体的には結構な人数が関わっていて、皆さんが頑張った成果だと思います!
紹介動画はこちら
この記事では、前回紹介したアニメーションを表示するために、もちろんオープンデータのAPIを利用して、データを取ってきているので、その辺りを書きたいと思います。
メトロのオープンデータAPIからデータ取得
※タイトルにも有るように、volleyとgsonを使っています、Androidのライブラリとして超有名なので、特に説明はいらないかと思います、知りたい方は申し訳ありませんがググって下さい。
このアプリでは、現在走行中の列車数を取得して、アニメーションを表示しています、取得に下記クラスを実装しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
public class GetTrainDataRequest implements TrainRequest.Callback { private static final String BEFORE_URL = "https://api.tokyometroapp.jp/api/v2/datapoints?rdf:type=odpt:Train&odpt:railway=odpt.Railway:TokyoMetro."; private static final int BASE_WAIT_TIME = 600; private static final int RUNDAM_WAIT_TIME = 1200; private Context _context; private HashMap<String, TrainLocationData> _locationHashMap; Handler _handler = new Handler(); private Callback _callback; public interface Callback { public void onAllRequestFinish(HashMap<String, TrainLocationData> locationMapData); public void onRequestFinish(TrainLocationData data); } public GetTrainDataRequest(Activity activity) { super(); _context = activity.getApplicationContext(); _callback = (Callback)activity; _locationHashMap = new HashMap<String, TrainLocationData>(); } public void run() { final GetTrainDataRequest _this = this; Random rnd = new Random(); // 路線数分遅延させながら取得 for (int i = 0; i < TrainConst.lineCodeList.length ; i++) { String code = TrainConst.lineCodeList[i]; new TrainRequest(_context, BEFORE_URL + code + "&acl:consumerKey=" + TrainConst.CUSTOMER_KEY, i, _this); try { Thread.sleep(rnd.nextInt(RUNDAM_WAIT_TIME) + BASE_WAIT_TIME); } catch (InterruptedException e) { e.printStackTrace(); } } } // 1路線分のデータ取得が終了した際に呼ばれる @Override public void onRequestFinish(TrainData[] data, int lineId) { TrainLocationData tld = new TrainLocationData(data, lineId); _locationHashMap.put("" + lineId, tld); _callback.onRequestFinish(tld); // 全ての路線情報が取得し終わったら通知 ※今回未使用 if (_locationHashMap.keySet().size() == TrainConst.MAX_LINE_COUNT) { _callback.onAllRequestFinish(_locationHashMap); _locationHashMap.clear(); } } } |
このクラスをインスタンス化してrunメソッドを呼べば、現在の全路線情報を取得してくれます、1路線の取得が完了する度にコールバックでデータが渡されるようになっています。
ここで注意なのは、一気に9路線分リクエストすると、リクエスト数の制限に引っかかってしまうので、遅延させながら取得しています。そんな事情もあり、画面上に表示される時は徐々に表示されていく形を取っています。
このクラスを使うActivityでは5分毎にrunメソッドを呼ぶようにして表示を更新しています。
上記クラスの中でTrainRequestというクラスを使っています、これはVolleyで指定のurlにリクエストを行い、gsonでデータをパースしています、ソースコードもテンプレのようなもので、特別なことはしていません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class TrainRequest { public interface Callback { public void onRequestFinish(TrainData[] data, int lineId); } public TrainRequest(Context context, String url, int lineId, Callback callback) { request(url, Volley.newRequestQueue(context), lineId, callback); } private void request(String url, RequestQueue queue, final int lineId, final Callback callback) { queue.add(new JsonArrayRequest(url, new Listener<JSONArray>() { @Override public void onResponse(JSONArray response) { TrainData[] td = new Gson().fromJson(response.toString(), TrainData[].class); callback.onRequestFinish(tld, lineId); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e(getClass().getName(), "TrainRequest error : " + error.getMessage()); } })); queue.start(); } } |
リクエストが終わったらgsonでTrainDataクラスにデータを格納しますが、オープンデータのレスポンスがJSON-LDなため、SerializedNameを使って、下記のような対応が必要でした。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
public class TrainData { @SerializedName("@context") public String context; @SerializedName("@id") public String id; @SerializedName("@type") public String type; @SerializedName("dc:date") public String date; @SerializedName("dct:valid") public String valid; @SerializedName("odpt:delay") public String delay; @SerializedName("odpt:frequency") public String frequency; @SerializedName("odpt:fromStation") public String fromStation; @SerializedName("odpt:railDirection") public String railDirection; @SerializedName("odpt:railway") public String railway; @SerializedName("odpt:startingStation") public String startingStation; @SerializedName("odpt:terminalStation") public String terminalStation; @SerializedName("odpt:toStation") public String toStation; @SerializedName("odpt:trainNumber") public String trainNumber; @SerializedName("odpt:trainOwner") public String trainOwner; @SerializedName("odpt:trainType") public String trainType; @SerializedName("owl:sameAs") public String sameAs; } |
実際の1列車情報のjsonは下記のようなデータで、列車数分が配列になって来ます。
1 |
{"@context":"http:\/\/vocab.tokyometroapp.jp\/context_odpt_Train.jsonld","odpt:trainNumber":"A1173S","odpt:delay":0,"odpt:startingStation":"odpt.Station:Tobu.Tojo.Kawagoeshi","odpt:terminalStation":"odpt.Station:TokyoMetro.Yurakucho.ShinKiba","odpt:railway":"odpt.Railway:TokyoMetro.Yurakucho","@type":"odpt:Train","odpt:trainType":"odpt.TrainType:TokyoMetro.Local","odpt:fromStation":"odpt.Station:TokyoMetro.Yurakucho.Wakoshi","odpt:trainOwner":"odpt.TrainOwner:TokyoMetro","odpt:toStation":"odpt.Station:TokyoMetro.Yurakucho.ChikatetsuNarimasu","dct:valid":"2015-02-26T12:12:41+09:00","odpt:railDirection":"odpt.RailDirection:TokyoMetro.ShinKiba","owl:sameAs":"odpt.Train:TokyoMetro.Yurakucho.A1173S","dc:date":"2015-02-26T12:11:11+09:00","@id":"urn:ucode:_00001C000000000000010000030CB98B","odpt:frequency":90} |
このような実装を行うことで、オープンデータAPIから値を取得し利用することが可能になります!
■最後に
やはりリクエストやパース処理を楽に実装出来たり、可読性を上げることができるのでこれらライブラリは本当に有用です。あとは、中身がなにやってるかは理解した上で利用できるともっと良いですね。