Google Image Search API を使用した android アプリを作成してみました。
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・)