WebAPIとは
Webサイトに外部のサイトの提供する機能や情報を組み込んだり、アプリケーションソフトからWeb上で公開されている機能や情報を利用できるサービス- メインスレッド(UIスレッド)で通信処理ができない
- UIスレッドでないとViewの編集ができない
- マニフェストに定義しないと通信処理できない
- JSONの使い方
アニメマップAPIの使い方
- WebAPIの基本的な動き 通信は基本的にXMLかJSONの2通りのやり方がある。
- アニメマップAPIへのリクエストとレスポンス アニメマップのAPIのサイト(http://animemap.net/pages/api/)を見ると地域ごとに取得できるみたい
- JSONを解析 JSONは{}で囲まれた領域に"変数名":"value"見たいな感じで定義される。
違いは取得するデータの形。試しに今週のアニメ情報で比較
XML | : | http://animemap.net/api/table/osaka.xml |
JSON | : | http://animemap.net/api/table/osaka.json |
大阪の番組表が欲しいので、リクエスト(サーバへの要求)はコレ(http://animemap.net/api/table/osaka.json)
実際にブラウザでこのURLに行くとJSON型がどんなデータが返ってくるのか確認できる
Androidで書くとこんな感じでリクエストして、戻り値で JSON 型をStringにする。
/** * アニメマップに大阪のテレビ情報をリクエスト. * * @return JSON型のレスポンスをStringで返す */ public static String getAnimeInfo() { // リクエスト AndroidHttpClient client = AndroidHttpClient.newInstance(null); HttpGet get = new HttpGet("http://animemap.net/api/table/osaka.json"); StringBuilder sb = new StringBuilder(); try { // リクエスト要求 ⇒ レスポンス HttpResponse response = client.execute(get); // レスポンスをStringにして返値にする BufferedReader br = new BufferedReader(new InputStreamReader( response.getEntity().getContent())); String line = null; while ((line = br.readLine()) != null) { sb.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { client.close(); } return sb.toString(); }
ほんとの定義はこの中にもInt型とかいろいろあるけど省略
レスポンスのJSONを改行や字下げとかで解析してみると、
{ "request":{ "type":"json", "url":"地域ごとの一覧URL", "updated":"更新時間" }, "response":{ "item":[ { "title":"アニメのタイトル", "url":"アニメの放送局一覧URL", "time":"放送時間", "station":"放送局", "state":"よくわらん", "next":"第X話", "episode":"総話数", "cable":"よくわからん", "today":"よくわからん", "week":"放送曜日" }, { "title":"アニメのタイトル", ………省略……… } ] } }このJSONは"request","response"の2つの連想配列を持ち、
"response"にはitemって配列([]←この記号は配列)に1アニメずつ連想配列があることがわかる
アニメ連想配列ごとに放送時間、放送局など色々な情報が含まれてるけど、とりあえずアニメのタイトル取得してリスト表示させようと思う
さっきのJSONをStringにしたヤツからアニメタイトル一覧を取得する関数を作る
/** * JSONからアニメのタイトルを抜き出す. * * @param str_json * @return */ public static String[] getTitleListForJSON(String jsonInfo) { final ArrayList<String> tmp = new ArrayList<String>(); try { // String型をJSON型に変換 JSONObject json = new JSONObject(jsonInfo); // "response"連想配列を取得 JSONObject responce = json.getJSONObject("response"); // "item"配列を配列型で取得 final JSONArray animes = responce.getJSONArray("item"); // "item"配列から1コずつ連想配列を取り出し、タイトルを出力用リストに入れてく for (int i = 0; i < animes.length(); i++) { JSONObject o = (JSONObject) animes.get(i); tmp.add(o.getString("title")); } } catch (JSONException e) { e.printStackTrace(); } return tmp.toArray(new String[0]); }
Androidの実装
次にAndroidでの描画を実装。これがまた面倒。。 最初に述べたようにAndroidはUIスレッドでは通信できない。ので、別スレッドでデータの取得を行う。でも、取得したデータは通信のスレッドではViewに入れることができない。よって、元のUIスレッドでViewに表示させる処理がいる、、 なに言ってるのかわからなくなるので、一個ずつ処理していく- ベース作り まず下準備。大本のマニフェストやレイアウトの設定
- Manifest.xml これ入れないと通信系動かないので注意!!
- MainActivity.java
- 通信用スレッド立てる もはやAndroid以前にjavaの問題なんだけど、別スレッドを立てるにはThreadクラスのインスタンスがいる。 Thread#start()メソッドを実行することで、Runnable#run()メソッドが別スレッドで実行される。
- Handler使ってUIスレッドで描画 現在通信スレッド上ににアニメタイトル一覧があるので、ここからViewにデータをセットしたい。そこで直面するのが「通信のスレッドではViewに入れることができない」問題。解決策はHandlerクラス
アニメのタイトル一覧をListViewで表示させる
<uses-sdk/>タグの後らへんに追記
<uses-permission android:name="android.permission.INTERNET" />
public class MainActivity extends Activity { ListView mListView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mListView = new ListView(this); mListView.setBackgroundColor(Color.BLACK); setContentView(mListView); } // 記載済みの為省略 public static String getAnimeInfo() {……} public static String[] getTitleForJSON(String jsonInfo) {……} }
ActivityにRunnableインターフェースをくっつけて、runを実装
public class MainActivity extends Activity implements Runnable { ListView mListView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mListView = new ListView(this); mListView.setBackgroundColor(Color.BLACK); setContentView(mListView); // スレッド起動!通信開始!! new Thread(this).start(); } // 記載済みの為省略 public static String getAnimeInfo() {……} public static String[] getTitleForJSON(String jsonInfo) {……} @Override public void run() { String jsonInfo = getAnimeInfo(); final String[] titles = getTitleForJSON(jsonInfo); for(String str:titles)Log.d("TEST","title = "+str); } }ログにアニメタイトル一覧が出ればOK!
HandlerとはHandlerのインスタンスを生成したスレッドで自信の処理を行う事ができる
つまり、UIスレッド(Mainスレッド)でHandlerを生成しといて、別スレッドでこのHandlerを使えばUIスレッドで処理してることになる。run()をちょっと修正
// UIスレッド上にHandler生成 Handler mHandler =new Handler(); //Activityのメンバ変数 @Override public void run() { String jsonInfo = getAnimeInfo(); final String[] titles = getTitleForJSON(jsonInfo); for(String str:titles)Log.d("TEST","title = "+str); // Handlerはpostメソッドで引数のRunnable#run()メソッドを自信の生成スレッド上で実行させる mHandler.post(new Runnable() { @Override public void run() { // ここの処理がUIスレッドで実行される mListView.setAdapter(new ArrayAdapter<String>(MainActivity.this .getApplicationContext(), android.R.layout.simple_expandable_list_item_1, titles)); } }); }
完成!
最終的なコードはこんだけ。行数短くしたかったからコメント無、可読性落とした
public class MainActivity extends Activity implements Runnable{ ListView mListView = null; Handler mHandler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(mListView = new ListView(this)); new Thread(this).start(); } public static String getAnimeInfo() { AndroidHttpClient client = AndroidHttpClient.newInstance(null); HttpGet get = new HttpGet("http://animemap.net/api/table/osaka.json"); StringBuilder sb = new StringBuilder(); try { HttpResponse response = client.execute(get); BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); String line = null; while ((line = br.readLine()) != null) sb.append(line); } catch (IOException e) { e.printStackTrace(); } finally { client.close(); } return sb.toString(); } public static String[] getTitleForJSON(String jsonInfo) { final ArrayList<String> tmp = new ArrayList<String>(); try { JSONArray json = new JSONObject(jsonInfo) .getJSONObject("response") .getJSONArray("item"); for (int i = 0; i < json.length(); i++) tmp.add(((JSONObject) json.get(i)).getString("title")); } catch (JSONException e){ e.printStackTrace(); } return tmp.toArray(new String[0]); } @Override public void run() { final String[] titles = getTitleForJSON(getAnimeInfo()); mHandler.post(new Runnable(){ @Override public void run(){ mListView.setAdapter(new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_expandable_list_item_1,titles)); } }); } }※マニフェストの追記は忘れない様に!
0 件のコメント:
コメントを投稿