サムネイルの表示
このチュートリアルではサムネイルの表示方法について学びます。
thumbnail.cgi と
command.cgi を使用します。
このチュートリアルは別項の
Android Tutorial 3:コンテンツのダウンロード
に基づいています。
サムネイルとファイル名をセットで表示し、インタラクティブなコンテンツリストにします。 アプリケーションの開始時は、ルートフォルダが表示されます。 リストは次のようになります:
コンテンツリストのイメージファイルをクリック(タップ)すると、 画像はこのように表示されます:
コンテンツリストのフォルダをクリック(タップ)すると、 その中身が表示されます:
子のコンテンツリストのイメージファイルをクリック(タップ)すると、 画像はこのように表示されます:
表示されているとおり、Android 端末に画像ファイルがダウンロードされます。
このチュートリアルでは、データの取得・表示のために、これまでに学んだコマンドを利用します。
アプリケーションを作成するために、次のファイルを作成します :
- MainActivity.java
- activity_main.xml
- ImageViewActivity.java
- activity_image_view.xml
重要: Android application
は、デフォルトの状態ではインターネットにアクセスすることができません。
そのため、設定ファイル
AndroidManifest.xml を変更し、権限を与える必要があります。
パス:
[Project_Folder]/AndroidManifest.xml
AndroidManifest.xml に以下のコードを追加してください:
<uses-permission android:name="android.permission.INTERNET" />
リストのレイアウト作成
ではまず、
activity_main.xml を記述して、レイアウトを決定します。
このファイルは、layout フォルダに配置されています。
パス:
[Project_Folder]/res/layout/activity_main.xml
activity_main.xml は Android Tutorial 3: コンテンツのダウンロードと同じになります。 実装の説明についてはそちらを参照してください。
イメージビューのレイアウト作成
次に、
activity_image_view.xml を記述して、レイアウトを決定します。
このファイルは、layout フォルダに配置されています。
パス:
[Project_Folder]/res/layout/activity_image_view.xml
activity_image_view.xml は Android Tutorial 3: コンテンツのダウンロードと同じになります。 実装の説明についてはそちらを参照してください。
コンテンツリストの作成
さて、
MainActivity.java を修正します。
まずは FlashAir の任意のフォルダにあるファイル名の一覧を取得します(詳細は
Android Tutorial 3: コンテンツのダウンロード
を確認してください)。
次に、リスト内の各ファイルのサムネイルを取得し、
ListView
にファイル名とサムネイルの情報を設定します。
リストはクリック可能にします。
初期化
コンテンツリストをクリックしたら、どの要素がクリックされたのかを判別し、画像を表示する必要があります。
onItemClick()
のクラス宣言の変更から開始します。
アプリケーションの開始時に、コンテンツリストを表示したいので、
Activity
クラスの
onCreate(Bundle savedInstanceState)
を修正します。
このコードは前回のチュートリアルの内容とよく似ていますが、いくつか異なっている点があります。
前回のチュートリアルのコードを再利用している場合は、変数の型や関数の呼び出しがこのチュートリアルのコードと一致していることを必ず確認してください。
SimpleAdapter
を使用する理由については後述します。
MainActivity.java (1)
public class MainActivity extends Activity implements AdapterView.OnItemClickListener {
ListView listView;
ImageView imageView;
TextView currentDirText;
TextView numFilesText;
Button backButton;
String rootDir = "DCIM";
String directoryName = rootDir; // Initialize to rootDirectory
SimpleAdapter listAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
// Set buttons
getWindow().setTitleColor(Color.rgb(65, 183, 216));
backButton = (Button)findViewById(R.id.button1);
backButton.getBackground().setColorFilter(Color.rgb(65, 183, 216), PorterDuff.Mode.SRC_IN);
backButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(directoryName.equals(rootDir)) {
listRootDirectory();
}
else {
int index = directoryName.lastIndexOf("/");
directoryName = directoryName.substring(0, index);
listDirectory(directoryName);
}
}
});
backButton.setEnabled(false); // Disable in root directory
listRootDirectory();
}
catch(Exception e) {
Log.e("ERROR", "ERROR: " + e.toString());
e.printStackTrace();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
ViewBinderの作成
ListView
を使用してサムネイルとファイル名のペアを表示します。
しかし、画像はプロジェクトフォルダの
Drawable
では静的管理していません。実行時に処理する必要があります。
ファイル名と関連付けられたサムネイルを操作するために、
Adapter
を使用します。 使用するのは上記で宣言している
SimpleAdapter
です。 サムネイルとファイル名を表示するのに、
SimpleAdapter
が正確なサムネイルとファイル名を map をできるよう、カスタムの
ViewBinder
を作成する必要があります。
MainActivity.java (2)
class CustomViewBinder implements ViewBinder {
@Override
public boolean setViewValue(View view, Object obj, String text) {
if((view instanceof ImageView) && (obj instanceof Drawable)) {
ImageView imageView = (ImageView) view;
BitmapDrawable thumbnail = (BitmapDrawable) obj;
imageView.setImageDrawable((Drawable)thumbnail);
return true;
}
return false;
}
}
コンテンツリストの作成
ファイル数を取得するためには、以下のコマンドを使用します。
- ファイル数は、
command.cgi
にop=101
とフォルダパスを指定することで取得できます。- コマンド:
http://flashair/command.cgi?op=101&DIR=/DCIM
- コマンドが返す情報:
<NumberofItems>
- コマンド:
ファイルデータを取得するためには、以下のコマンドを使用します。
- ファイルデータは、
command.cgi
にop=100
とフォルダパスを指定することで取得できます。- コマンド:
http://flashair/command.cgi?op=100&DIR=/DCIM
- コマンドが返す情報:
<Directory>,<Filename>,<Size>,<Attribute>,<Date>,<Time>
- コマンド:
サムネイルを取得するためには、以下のコマンドを使用します:
thumbnail.cgi
はバラメータにファイルパスを指定して使用します。- コマンド:
http://flashair/thumbnail.cgi?directoryPath/fileName
- コマンドが返す情報:
<EXIF_thumbnail_image>
- コマンド:
キー
"thmb"
と、ファイル名の
"fname"
を
Map
オブジェクトに設定します。
この
Map
オブジェクトは 前述した
SimpleAdapter
で使用される
ArrayList
に追加されます。
ファイルは
Bitmap
オブジェクトで読み込みます。
コマンドの実行には前項 Android Tutorial 3: コンテンツのダウンロードまでに作成した、 FlashAirRequest.java を使用します。
listRootDirectory()
と
listDirectory(directoryName)
は
onCreate(Bundle savedInstanceState)
で呼ばれ、コンテンツを取得し表示するものです。
詳細は
Android Tutorial 3: コンテンツのダウンロード で説明しています。
MainActivity.java (3)
public void listRootDirectory() {
directoryName = rootDir;
listDirectory(directoryName);
}
public void listDirectory(String dir) {
// Prepare command directory path
if(dir.equals(rootDir)) {
backButton.setEnabled(false);
}
else {
backButton.setEnabled(true);
}
currentDirText = (TextView)findViewById(R.id.textView1);
currentDirText.setText(dir + "/");
dir = "/" + dir;
ArrayList <NameValuePair> httpParams = new ArrayList <NameValuePair> ();
httpParams.add(new BasicNameValuePair("DIR", dir));
dir = URLEncodedUtils.format (httpParams, "UTF-8" );
numFilesText = (TextView)findViewById(R.id.textView2);
// Fetch number of items in directory and display in a TextView
new AsyncTask<String, Void, String>(){
@Override
protected String doInBackground(String... params) {
String dir = params[0];
String fileCount = FlashAirRequest.getString("http://flashair/command.cgi?op=101&" + dir);
return fileCount;
}
@Override
protected void onPostExecute(String fileCount) {
numFilesText.setText("Items Found: " + fileCount);
}
}.execute(dir);
// Fetch list of items in directory and display in a ListView
new AsyncTask<String, Void, ListAdapter>(){
@Override
protected ListAdapter doInBackground(String... params) {
String dir = params[0];
ArrayList <String> fileNames = new ArrayList <String>();
String files = FlashAirRequest.getString("http://flashair/command.cgi?op=100&" + dir);
String[] allFiles = files.split("([,\n])"); // split by newline or comma
for(int i = 2; i < allFiles.length; i= i + 6) {
if(allFiles[i].contains(".")) {
// File
fileNames.add(allFiles[i]);
}
else { // Directory, append "/"
fileNames.add(allFiles[i] + "/");
}
}
// Get thumbnails
ArrayList<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
for(int i = 0; i < fileNames.size(); i++) {
String fileName = "";
fileName = "http://flashair/thumbnail.cgi?" + directoryName + "/" + fileNames.get(i);
Map<String, Object> entry = new HashMap<String, Object>();
BitmapDrawable drawnIcon = null;
if( (fileName.toLowerCase(Locale.getDefault()).endsWith(".jpg")) || (fileName.toLowerCase(Locale.getDefault()).endsWith(".jpeg")) ) {
Bitmap thumbnail = FlashAirRequest.getBitmap(fileName);
drawnIcon = new BitmapDrawable(getResources(), thumbnail);
}
if(drawnIcon == null) {
entry.put("thmb", R.drawable.ic_launcher);
}
else {
entry.put("thmb", drawnIcon);
}
entry.put("fname", fileNames.get(i)); // Put file name onto the map
data.add(entry);
}
// Set the file list to a widget
listAdapter = new SimpleAdapter(MainActivity.this,
data,
android.R.layout.activity_list_item,
new String[]{"thmb", "fname"},
new int[]{android.R.id.icon, android.R.id.text1});
listAdapter.setViewBinder(new CustomViewBinder());
return listAdapter;
}
@Override
protected void onPostExecute(ListAdapter listAdapter) {
listView = (ListView)findViewById(R.id.listView1);
ColorDrawable divcolor = new ColorDrawable(Color.rgb(17, 19, 58));
listView.setDivider(divcolor);
listView.setDividerHeight(1);
listView.setAdapter(listAdapter);
listView.setOnItemClickListener(MainActivity.this);
}
}.execute(dir);
}
thumbnail.cgi
は、EXIFデータを持ったJPEGファイルの場合にのみ、サムネイルを返すことに注意してください。
-
60行目
JPEG ファイルであるか判別しています。
ファイルが JPEG であった場合は、EXIFデータを持っているかを判別しています(64行目)。EXIFデータを持っているかどうかは、BitmapDrawable
を使用して試験的に保存し、サムネイルがnullであるかどうかで決定しています。 -
64-66行目
サムネイルを持っていない場合に、Androidのアイコンを設定しています。 -
86-91行目
新規のListView
を作成しています。
サムネイルとファイル名がそれぞれ view にバインドされています。 作成したViewをレイアウトに設定しています。 -
75-80行目
新規のAdapter
とCustomViewBinder
を生成しています。
これらは、90行目でListView
にバインドされています。
クリックリスナーの設定
Android Tutorial 3: コンテンツのダウンロード と同様の設定を行います:
- フォルダをクリックした場合は、選択したフォルダのコンテンツを表示した画面を表示します。
- ファイルをクリックした場合は、ファイルをダウンロードし、ダウンロードした画像を表示しした画面を表示します。
リストの動作は同じですが、書式が異なっています。 (
ListView
の
Adapter
が
Map
オブジェクトとして構成されています。)
この変更に対応するために
onItemClick()
をオーバーライドします:
MainActivity.java (4)
@Override
public void onItemClick(AdapterView<?> l, View v, int position, long id) {
Object item = l.getItemAtPosition(position); // Get item at clicked position in list of files
if(item instanceof Map<?, ?>) {
Map<String, Object> mapItem = (Map<String, Object>) item;
Object downloadFile = mapItem.get("fname");
if(downloadFile.toString().endsWith("/")) {
// Directory, remove "/" and show content list
String dirName = downloadFile.toString().substring(0, downloadFile.toString().length()-1); // All but the "/"
directoryName = directoryName + "/" + dirName;
listDirectory(directoryName);
}
else if( (downloadFile.toString().toLowerCase(Locale.getDefault()).endsWith(".jpg")) || (downloadFile.toString().toLowerCase(Locale.getDefault()).endsWith(".jpeg"))
|| (downloadFile.toString().toLowerCase(Locale.getDefault()).endsWith(".jpe")) || (downloadFile.toString().toLowerCase(Locale.getDefault()).endsWith(".png")) ) {
// Image file, download using ImageViewActivity
Intent viewImageIntent = new Intent(this, ImageViewActivity.class);
viewImageIntent.putExtra("downloadFile", downloadFile.toString());
viewImageIntent.putExtra("directoryName", directoryName);
MainActivity.this.startActivity(viewImageIntent);
}
}
}
} // End MainActivity class
- 4-6行目
Map
オブジェクトを使用して、ListView
で選択されたファイル名を取得しています。
画像表示画面の作成
class ImageViewActivity
は
Android Tutorial 3: コンテンツのダウンロードと同じです。
実装の詳細についてはこちらのチュートリアルを参照してください。
サンプルコード
android_tutorial_04.zip (533KB)
このサイトのサンプルコードは二条項BSDライセンスで提供されています。