Google Image Search API は以下のサイトにあるように、q=xxx の部分で検索キーワードを指定します。
応答は JSON フォーマットです。
Google Image Search API
検索例: 高知城
リクエスト
レスポンス
{"responseData": {"results":[{"GsearchResultClass":"GimageSearch","width":"600","height":"400","imageId":"Ehuk98rEYswf5M:","tbWidth":"135","tbHeight":"90","unescapedUrl":"http://img01.kitaguni.tv/usr/akkesi1946/1%E9%AB%98%E7%9F%A5%E5%9F%8E.jpg","url":"http://img01.kitaguni.tv/usr/akkesi1946/1%25E9%25AB%2598%25E7%259F%25A5%25E5%259F%258E.jpg","visibleUrl":"akkesi1946.kitaguni.tv","title":"風のふくまま・・・:\u003cb\u003e高知城\u003c/b\u003e","titleNoFormatting":"風のふくまま・・・:高知城","originalContextUrl":"http://akkesi1946.kitaguni.tv/e543472.html","content":"\u003cb\u003e高知城\u003c/b\u003e","contentNoFormatting":"高知城","tbUrl":"http://images.google.com/images?q\u003dtbn:Ehuk98rEYswf5M::img01.kitaguni.tv/usr/akkesi1946/1%25E9%25AB%2598%25E7%259F%25A5%25E5%259F%258E.jpg"},{"GsearchResultClass":"GimageSearch","width":"420","height":"313","imageId":"MHxe0rjkGw3MRM:","tbWidth":"125","tbHeight":"93","unescapedUrl":"http://ozu.cc.kochi-u.ac.jp/~fuchu/syakai/top_img2%5B1%5D.jpg","url":"http://ozu.cc.kochi-u.ac.jp/~fuchu/syakai/top_img2%255B1%255D.jpg","visibleUrl":"ozu.cc.kochi-u.ac.jp","title":"top_img2[1].jpg","titleNoFormatting":"top_img2[1].jpg","originalContextUrl":"http://ozu.cc.kochi-u.ac.jp/~fuchu/syakai/kochicastle.html","content":"\u003cb\u003e高知城\u003c/b\u003e","contentNoFormatting":"高知城","tbUrl":"http://images.google.com/images?q\u003dtbn:MHxe0rjkGw3MRM::ozu.cc.kochi-u.ac.jp/~fuchu/syakai/top_img2%255B1%255D.jpg"},{"GsearchResultClass":"GimageSearch","width":"640","height":"480","imageId":"7H2hzs-xvZA-kM:","tbWidth":"137","tbHeight":"103","unescapedUrl":"http://map.papanavi.jp/ucan/img/sho/39000373_1.jpg","url":"http://map.papanavi.jp/ucan/img/sho/39000373_1.jpg","visibleUrl":"map.papanavi.jp","title":"\u003cb\u003e高知城\u003c/b\u003e | パパナビ","titleNoFormatting":"高知城 | パパナビ","originalContextUrl":"http://map.papanavi.jp/p/spot/details/S39000373-001","content":"\u003cb\u003e高知城\u003c/b\u003e","contentNoFormatting":"高知城","tbUrl":"http://images.google.com/images?q\u003dtbn:7H2hzs-xvZA-kM::map.papanavi.jp/ucan/img/sho/39000373_1.jpg"},{"GsearchResultClass":"GimageSearch","width":"2048","height":"1536","imageId":"6K73uOHjLlHRpM:","tbWidth":"150","tbHeight":"113","unescapedUrl":"http://userdisk.webry.biglobe.ne.jp/008/871/08/N000/000/000/121957888604916210164.JPG","url":"http://userdisk.webry.biglobe.ne.jp/008/871/08/N000/000/000/121957888604916210164.JPG","visibleUrl":"takachin0413.at.webry.info","title":"たかちゃんの独り言/ウェブリブログ","titleNoFormatting":"たかちゃんの独り言/ウェブリブログ","originalContextUrl":"http://takachin0413.at.webry.info/","content":"山内一豊の\u003cb\u003e高知城\u003c/b\u003eです。","contentNoFormatting":"山内一豊の高知城です。","tbUrl":"http://images.google.com/images?q\u003dtbn:6K73uOHjLlHRpM::userdisk.webry.biglobe.ne.jp/008/871/08/N000/000/000/121957888604916210164.JPG"}],"cursor":{"pages":[{"start":"0","label":1},{"start":"4","label":2},{"start":"8","label":3},{"start":"12","label":4},{"start":"16","label":5},{"start":"20","label":6},{"start":"24","label":7},{"start":"28","label":8}],"estimatedResultCount":"392000","currentPageIndex":0,"moreResultsUrl":"http://www.google.com/images?oe\u003dutf8\u0026ie\u003dutf8\u0026source\u003duds\u0026start\u003d0\u0026hl\u003dja\u0026q\u003d%E9%AB%98%E7%9F%A5%E5%9F%8E"}}, "responseDetails": null, "responseStatus": 200}
今回のサンプル・アプリでは、"title" と "unescapedUrl" の値を利用しています。
JSON は階層構造になっているので、こららの値を取得するには、
"responseData" --> "results" と値を辿っていく必要があります。
JSON の解析は、org.json.JSONObject か org.json.JSONArray を使うと簡単に行えます。
"responseData" は値が1つのなので、JSONObject を、
"results" は値が複数(4つ)なので、JSONArray を使用します。
ポイントは、こんなところです。
サンプル・アプリは、3つの要素で構成しています。
- 検索キーワードを入力する EditText
- 検索処理を開始する Button
- 検索結果を表示する ListView
ListView の項目をクリックすると、
別途 Activity を起動し、画像を表示させるようにしています。
メイン Activity のレイアウトです。
main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <EditText android:id="@+id/keyword" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="高知城" /> <Button android:id="@+id/search" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="イメージ検索" /> <ListView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="2" /> </LinearLayout>
メイン Activity です。
JsonTestActivity.java
package jp.kochi.rtaki; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.Toast; import android.widget.AdapterView.OnItemClickListener; public class JsonTestActivity extends Activity { private static final String QUERY_URL = "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q="; private ListView mListView = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button search = (Button) findViewById(R.id.search); search.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { EditText keyword = (EditText) findViewById(R.id.keyword); String key = keyword.getText().toString(); updateList(key); } }); mListView = (ListView) findViewById(R.id.list); mListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Map map = (Map) parent.getItemAtPosition(position); String url = (String) map.get("unescapedUrl"); Intent intent = new Intent(); intent.setClass(JsonTestActivity.this, ImageActivity.class); intent.putExtra("url", url); startActivity(intent); } }); } private void updateList(String key) { ArrayList listData = requestImageSearch(key); SimpleAdapter adapter = new SimpleAdapter(this, listData, android.R.layout.simple_list_item_1, new String[] { "title" }, new int[] { android.R.id.text1 }); mListView.setAdapter(adapter); } private ArrayList requestImageSearch(String key) { Map<String, Object> temp; ArrayList<Map> listData = new ArrayList<Map>(); String encodeKey = Uri.encode(key); HttpClient client = new DefaultHttpClient(); String req = QUERY_URL + encodeKey; Log.v("JsonTest", "query :" + req); HttpUriRequest httpUriReq = new HttpGet(req); try { HttpResponse res = client.execute(httpUriReq); if (res.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { Toast.makeText(JsonTestActivity.this, "StatusCode = " + res.getStatusLine().getStatusCode(), Toast.LENGTH_LONG).show(); } else { String entity = EntityUtils.toString(res.getEntity()); JSONObject jsonObj = new JSONObject(entity); String responseStatus = jsonObj.getString("responseStatus"); Log.v("JsonTest", "responseStatus :" + responseStatus); if (responseStatus.equals("200") != true) { Toast.makeText(JsonTestActivity.this, "responseStatus = " + responseStatus, Toast.LENGTH_LONG).show(); } else { JSONObject jsonObjData = jsonObj .getJSONObject("responseData"); JSONArray jsonObjResultArray = jsonObjData .getJSONArray("results"); for (int i = 0; i < jsonObjResultArray.length(); i++) { JSONObject jsonObjResult = jsonObjResultArray .getJSONObject(i); Log.v("JsonTest", "title :" + jsonObjResult.getString("title")); Map map = new HashMap<String, String>(); map.put("title", jsonObjResult.getString("title")); map.put("unescapedUrl", jsonObjResult .getString("unescapedUrl")); listData.add(map); } } } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JSONException e) { e.printStackTrace(); } return listData; } }
image.xml と ImageActivity.java は、ListView の項目をクリックしたときに、
画像を表示させる Activity です。
image.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> </LinearLayout>
ImageActivity.java
package jp.kochi.rtaki; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.widget.ImageView; public class ImageActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.image); Intent intent = getIntent(); String url = intent.getStringExtra("url"); Bitmap bitmap = getImage(url); ImageView image = (ImageView) findViewById(R.id.image); image.setImageBitmap(bitmap); } private Bitmap getImage(String url) { Bitmap bitmap = null; InputStream in = null; BufferedOutputStream out = null; byte[] buf = new byte[512]; int bytes; try { in = new BufferedInputStream(new URL(url).openStream(), 512); final ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); out = new BufferedOutputStream(dataStream, 512); while ((bytes = in.read(buf)) > 0) { out.write(buf, 0, bytes); } out.flush(); final byte[] data = dataStream.toByteArray(); BitmapFactory.Options options = new BitmapFactory.Options(); // options.inSampleSize = 1; bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options); } catch (IOException e) { e.printStackTrace(); } finally { try { if (in != null) in.close(); if (out != null) out.close(); } catch (IOException e) { e.printStackTrace(); } } return bitmap; } }
マニフェスト・ファイルは、青字の2行を追加しています。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="jp.kochi.rtaki" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".JsonTestActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".ImageActivity" /> </application> <uses-permission android:name="android.permission.INTERNET" /> <uses-sdk android:minSdkVersion="4" /> </manifest>
以上、はじめてマッッシュアップでした~(・o・)