iTunes APIとは
登録不要で使えて、例えば、
https://itunes.apple.com/search?term=beatles&country=JP&lang=ja_jp&media=music
で、「beatles」を検索すると、
{
"resultCount":50,
"results": [
{
"wrapperType":"track",
"kind":"song",
"artistId":136975,
"collectionId":458032395,
"trackId":458032429,
"artistName":"ビートルズ",
"collectionName":"1",
"trackName":"Let It Be",
"collectionCensoredName":"1",
"trackCensoredName":"Let It Be",
"artistViewUrl":"https://itunes.apple.com/jp/artist/bitoruzu/id136975?uo=4",
"collectionViewUrl":"https://itunes.apple.com/jp/album/let-it-be/id458032395?i=458032429&uo=4",
"trackViewUrl":"https://itunes.apple.com/jp/album/let-it-be/id458032395?i=458032429&uo=4",
"previewUrl":"http://a1770.phobos.apple.com/us/r1000/059/Music4/v4/cf/b4/36/cfb43624-f3e0-269f-f81a-911f9876732c/mzaf_4722855266064184302.plus.aac.p.m4a",
"artworkUrl30":"http://is5.mzstatic.com/image/pf/us/r30/Features/85/fe/95/dj.kfrgxzbp.30x30-50.jpg",
"artworkUrl60":"http://is4.mzstatic.com/image/pf/us/r30/Features/85/fe/95/dj.kfrgxzbp.60x60-50.jpg",
"artworkUrl100":"http://is1.mzstatic.com/image/pf/us/r30/Features/85/fe/95/dj.kfrgxzbp.100x100-75.jpg",
"collectionPrice":2000.00,
"trackPrice":250.00,
"releaseDate":"2000-11-13T08:00:00Z",
"collectionExplicitness":"notExplicit",
"trackExplicitness":"notExplicit",
"discCount":2,
"discNumber":1,
"trackCount":27,
"trackNumber":26,
"trackTimeMillis":230773,
"country":"JPN",
"currency":"JPY",
"primaryGenreName":"ロック"
}, {
...
}, {
...
}
]
}
が返ってきます。
今回は、
- trackName(曲や動画のタイトル)
- artistName(アーティスト名)
- artworkUrl100(アートワーク画像URL)
- previewUrl(曲や動画の試聴用データURL)
あたりを使って、Androidアプリを作ってみます。
プロジェクトを作成する
自動importを設定する
Preferences > Editor > General > Auto Import >
Volleyをインストールする
build.gradleに設定を書く
build.gradle (Module: app)を開いて、dependenciesの中に以下を追加します。
compile 'com.mcxiaoke.volley:library:1.0.16'
インストールする
iTunes APIと通信して、結果を一覧画面に表示する
Volleyで使う画像キャッシュクラスを作る
ルートパッケージ上で右クリックして、New > Java Class。
以下のように書きます。先頭行のpackageの行は書いてませんので、コピペするときはpackageの行を消さないように気をつけてください。
import android.graphics.Bitmap;
import android.util.LruCache;
import com.android.volley.toolbox.ImageLoader;
class LruImageCache implements ImageLoader.ImageCache {
private LruCache<String, Bitmap> mCache;
public LruImageCache() {
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;
mCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getByteCount() / 1024;
}
};
}
@Override
public Bitmap getBitmap(String url) {
return mCache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
mCache.put(url, bitmap);
}
}
これは、メモリ内に、使用可能なメモリ内の一定の量まで画像をキャッシュし、いっぱいになったら使用頻度が低い画像から破棄されるようになっています。
一覧画面のClassを作る
ルートパッケージ上で右クリックして、New > Activity > Blank Activity。
Launcher ActivityをONにすると、アプリ起動時に表示される画面になります。
3つのファイルが作成されます。ListActivity.javaは、Java Classで処理を書くところです。activity_list.xmlは、画面のレイアウトを書くところです。menu_list.xmlは、メニューを書くところです。
加えて、AndroidManifest.xmlにも、activity要素が追加されます。Java ClassからActivityを作成した場合は、自分でAndroidManifest.xmlに追加する必要があります。AndroidManifest.xmlに追加しないで呼び出そうとすると実行時エラーになります。activity要素の下のintent-filter要素は、アプリ起動時に表示される画面であることが書かれています(Launcher ActivityをONで作成した場合)。
今回はメニューを使わないので、ListActivityのonCreateOptionsMenu(Menu)とonOptionsItemSelected(MenuItem)は削除していいです。menu_list.xmlも削除していいです。
インターネットを使う権限を設定する
AndroidManifest.xmlを開いて、manifest要素の中に以下を追加します。これを書かないと、このアプリからインターネットを使うことができません。
<uses-permission android:name="android.permission.INTERNET" />
一覧画面のActionBarのタイトルをアプリ名にする
AndroidManifest.xmlを開いて、activity要素のandroid:label属性を以下のように変更します。
<activity
android:name=".ListActivity"
android:label="@string/app_name" >
一覧画面のLayout XMLを書く
activity_list.xmlを開いて、以下のように書きます。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.kentoriumi.itunesmusicsearch.ListActivity">
<EditText android:id="@+id/edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:hint="Keyword"
android:inputType="text"/>
<ListView android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_below="@id/edit_text"/>
</RelativeLayout>
一覧画面の行のLayout XMLを書く
app/res/layout上で右クリックして、New > Layout resource file。
list_item.xmlを開いて、以下のように書きます。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
<ImageView
android:id="@+id/image_view"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginRight="10dp"/>
<TextView android:id="@+id/track_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@id/image_view"
android:ellipsize="end"
android:lines="1"
android:textSize="20sp"
tools:text="track"/>
<TextView android:id="@+id/artist_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@id/image_view"
android:ellipsize="end"
android:lines="1"
tools:text="artist"/>
</RelativeLayout>
再度、activity_list.xmlを開いて、ListView要素の中に以下を追記すると、プレビューの一覧画面に先ほど作った行が表示されるようになります。
<ListView android:id="@+id/list_view"
...
tools:listitem="@layout/list_item"/>
Volleyを準備する
ListActivity.javaを開いて、ListActivityの中に
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
を、onCreate(Bundle)の中に
mRequestQueue = Volley.newRequestQueue(this);
mImageLoader = new ImageLoader(mRequestQueue, new LruImageCache());
を追加します。importの追加を聞かれたらOKしてください。
行を表示する処理を書く
ListActivity.javaを開いて、ListActivityの中に以下を追加します。importの追加を聞かれたらOKしてください。Adapterは、ListViewのように、保持している大量のデータの中から一部だけを表示するViewを使うときに、Viewとデータの橋渡しをします。
private class ListAdapter extends ArrayAdapter<JSONObject> {
public ListAdapter(Context context, int resource) {
super(context, resource);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
// 再利用可能なViewがない場合は作る
convertView = getLayoutInflater().inflate(R.layout.list_item, null);
}
ImageView imageView = (ImageView) convertView.findViewById(R.id.image_view);
TextView trackTextView = (TextView) convertView.findViewById(R.id.track_text_view);
TextView artistTextView = (TextView) convertView.findViewById(R.id.artist_text_view);
ImageLoader.ImageContainer imageContainer = (ImageLoader.ImageContainer) imageView.getTag();
if (imageContainer != null) {
imageContainer.cancelRequest(); // 画像取得中のリクエストをキャンセルする(再利用された時)
}
imageView.setImageBitmap(null); // 残ってる画像を消す(再利用された時)
// 表示する行番号のデータを取り出す
JSONObject result = getItem(position);
ImageLoader.ImageListener listener = ImageLoader.getImageListener(imageView, 0, 0);
imageView.setTag(mImageLoader.get(result.optString("artworkUrl100"), listener));
trackTextView.setText(result.optString("trackName"));
artistTextView.setText(result.optString("artistName"));
return convertView;
}
}
さらに、ListActivityの中に
private ListAdapter mAdapter;
を、onCreate(Bundle)の中に
mAdapter = new ListAdapter(this, R.layout.list_item);
ListView listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(mAdapter);
を追加します。先ほど作ったAdapterをListViewに設定してます。
検索の処理を書く
ListActivity.javaを開いて、ListActivityの中に以下を追加します。importの追加を聞かれたらOKしてください。View.OnKeyListenerは、キーボードのキーを押されたりしたときに呼び出されるところです。Enterキーが上がったときに検索処理を実行し、実行結果をAdapterに詰める(詰めたら画面は随時更新される)処理を書いています。
private class OnKeyListener implements View.OnKeyListener {
@Override
public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
if (keyEvent.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_ENTER) {
EditText editText = (EditText) view;
// キーボードを閉じる
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
String text = editText.getText().toString();
try {
// url encode 例. スピッツ > %83X%83s%83b%83c
text = URLEncoder.encode(text, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e("", e.toString(), e);
return true;
}
if (!TextUtils.isEmpty(text)) {
String url =
"https://itunes.apple.com/search?term=" + text + "&country=JP&media=music&lang=ja_jp";
mRequestQueue.add(new JsonObjectRequest(Request.Method.GET, url,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Log.d("", response.toString());
mAdapter.clear();
JSONArray results = response.optJSONArray("results");
if (results != null) {
for (int i = 0; i < results.length(); i++) {
mAdapter.add(results.optJSONObject(i));
}
}
}
},
null));
}
return true;
}
return false;
}
}
さらに、onCreate(Bundle)の中に
final EditText editText = (EditText) findViewById(R.id.edit_text);
editText.setOnKeyListener(new OnKeyListener());
を追加します。先ほど作ったOnKeyListenerをEditTextに設定してます。
ここまでで、ListActivity.javaは以下のようになってるはずです。先頭行のpackageの行は書いてませんので、コピペするときはpackageの行を消さないように気をつけてください。
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class ListActivity extends Activity {
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private ListAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
mRequestQueue = Volley.newRequestQueue(this);
mImageLoader = new ImageLoader(mRequestQueue, new LruImageCache());
mAdapter = new ListAdapter(this, R.layout.list_item);
ListView listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(mAdapter);
}
private class ListAdapter extends ArrayAdapter<JSONObject> {
public ListAdapter(Context context, int resource) {
super(context, resource);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
// 再利用可能なViewがない場合は作る
convertView = getLayoutInflater().inflate(R.layout.list_item, null);
}
ImageView imageView = (ImageView) convertView.findViewById(R.id.image_view);
TextView trackTextView = (TextView) convertView.findViewById(R.id.track_text_view);
TextView artistTextView = (TextView) convertView.findViewById(R.id.artist_text_view);
ImageLoader.ImageContainer imageContainer = (ImageLoader.ImageContainer) imageView.getTag();
if (imageContainer != null) {
imageContainer.cancelRequest(); // 画像取得中のリクエストをキャンセルする(再利用された時)
}
imageView.setImageBitmap(null); // 残ってる画像を消す(再利用された時)
// 表示する行番号のデータを取り出す
JSONObject result = getItem(position);
ImageLoader.ImageListener listener = ImageLoader.getImageListener(imageView, 0, 0);
imageView.setTag(mImageLoader.get(result.optString("artworkUrl100"), listener));
trackTextView.setText(result.optString("trackName"));
artistTextView.setText(result.optString("artistName"));
return convertView;
}
}
private class OnKeyListener implements View.OnKeyListener {
@Override
public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
if (keyEvent.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_ENTER) {
EditText editText = (EditText) view;
// キーボードを閉じる
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
String text = editText.getText().toString();
try {
// url encode 例. スピッツ > %83X%83s%83b%83c
text = URLEncoder.encode(text, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e("", e.toString(), e);
return true;
}
if (!TextUtils.isEmpty(text)) {
String url =
"https://itunes.apple.com/search?term=" + text + "&country=JP&media=music&lang=ja_jp";
mRequestQueue.add(new JsonObjectRequest(Request.Method.GET, url,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Log.d("", response.toString());
mAdapter.clear();
JSONArray results = response.optJSONArray("results");
if (results != null) {
for (int i = 0; i < results.length(); i++) {
mAdapter.add(results.optJSONObject(i));
}
}
}
},
null));
}
return true;
}
return false;
}
}
}
実行してみましょう
詳細画面に遷移して、試聴する
詳細画面のClassを作る
ルートパッケージ上で右クリックして、New > Activity > Blank Activity。
今回はメニューを使わないので、DetailActivityのonCreateOptionsMenu(Menu)とonOptionsItemSelected(MenuItem)は削除していいです。menu_detail.xmlも削除していいです。
詳細画面のLayout XMLを書く
activity_detail.xmlを開いて、以下のように書きます。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.kentoriumi.itunesmusicsearch.DetailActivity">
<VideoView android:id="@+id/video_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
一覧画面から詳細画面に遷移する処理を書く
ListActivity.javaを開いて、ListActivityの中に以下を追加します。importの追加を聞かれたらOKしてください。AdapterView.OnItemClickListenerは、ListViewの行がタップされたときに呼び出されるところです。タップされた行番号のデータを取り出し、必要なデータを詳細画面に渡しています。
private class OnItemClickListener implements AdapterView.OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
Intent intent = new Intent(ListActivity.this, DetailActivity.class);
// タップされた行番号のデータを取り出す
JSONObject result = mAdapter.getItem(position);
intent.putExtra("track_name", result.optString("trackName"));
intent.putExtra("preview_url", result.optString("previewUrl"));
startActivity(intent);
}
}
さらに、onCreate(Bundle)の中に
listView.setOnItemClickListener(new OnItemClickListener());
を追加します。先ほど作ったOnItemClickListenerをListViewに設定してます。
詳細画面で試聴する処理を書く
DetailActivity.javaを開いて、以下のように書きます。先頭行のpackageの行は書いてませんので、コピペするときはpackageの行を消さないように気をつけてください。
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.MediaController;
import android.widget.VideoView;
public class DetailActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
// ActionBarのタイトルを設定する
String trackName = getIntent().getExtras().getString("track_name");
getActionBar().setTitle(trackName);
String previewUrl = getIntent().getExtras().getString("preview_url");
if (!TextUtils.isEmpty(previewUrl)) {
VideoView videoView = (VideoView) findViewById(R.id.video_view);
videoView.setMediaController(new MediaController(this)); // 再生ボタンとかをつける
videoView.setVideoURI(Uri.parse(previewUrl)); // URLを設定する
videoView.start(); // 再生する
}
}
}
実行してみましょう
おわり。お疲れさまでした。
完成品はここにあります
AndroidStudioのプロジェクト構成になっているので、Eclipseの場合はごにょごにょしてください。
https://codebreak.com/git/kenchan1837/iTunesMusicSearchAndroid/