2011年9月22日木曜日

[Android] GridView内に非同期で画像を表示する方法

このエントリーをはてなブックマークに追加


【構成】

【AsyncGridViewActivity.java -メインアクティビティー】
package com.ayakix;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.widget.GridView;

public class AsyncGridViewActivity extends Activity {
private GridView gv;
private List urlList;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// グリッドビュー
gv = (GridView) findViewById(R.id.gv);
// ダウンロードURLリスト
urlList = new ArrayList();

urlList.add("http://example.com/test.png");

gv.setAdapter(new ImageGridViewAdapter(this, urlList));
gv.invalidate();
}
}


【ImageDownloadTask.java -非同期の画像ダウンローダー】
package com.ayakix;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.net.URL;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.util.Log;
import android.widget.ImageView;

public class ImageDownloadTask {
private ImageView iv;
private String url;
private Bitmap bitmap;

public ImageDownloadTask(ImageView iv, String url){
this.iv = iv;
this.url = url;
}

public void execute(){
final Handler mHandler = new Handler();
new Thread(new Runnable() {
public void run() {
bitmap = getBitmap(url);
if(bitmap == null) return;
// ポスト処理
mHandler.post(new Runnable() {
public void run() {
// 画像のセット
iv.setImageBitmap(bitmap);
}
});
}
}).start();
}

/*
* 画像のダウンロード
*/
public Bitmap getBitmap(String url){
Bitmap bitmap = null;
try{
BufferedInputStream in = new BufferedInputStream((InputStream) (new URL(url)).getContent());
bitmap = BitmapFactory.decodeStream(in);
in.close();
} catch (Exception ex){
return null;
}
return bitmap;
}
}


【ImageGridViewAdapter - グリッドビューアダプター】
package com.ayakix;

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;

public class ImageGridViewAdapter extends BaseAdapter {
private List urlList;
private LayoutInflater inflater;

static class ViewHolder{
ImageView iv_image;
}

public ImageGridViewAdapter(Context context, List urlList) {
this.urlList = urlList;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
ViewHolder holder;
if (view == null) {
holder = new ViewHolder();
view = inflater.inflate(R.layout.imagegridview, null);
// 画像
holder.iv_image = (ImageView) view.findViewById(R.id.imagegridview_iv_image);
// 画像の非同期DL
new ImageDownloadTask(holder.iv_image, urlList.get(position)).execute();
// 登録
view.setTag(holder);
} else {
holder = (ViewHolder)view.getTag();
}
return view;
}

@Override
public long getItemId(int position) {
return 0;
}

@Override
public Object getItem(int position) {
return null;
}

@Override
public int getCount() {
return urlList.size();
}
}


【imagegridview.xml -グリッドビューの各要素のレイアウト定義】
<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<!-- 写真 -->
<ImageView
android:id="@+id/imagegridview_iv_image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:adjustViewBounds="true"
/>
</RelativeLayout>


【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"
>
<GridView
android:id="@+id/gv"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:verticalSpacing="10sp"
android:horizontalSpacing="10sp"
android:numColumns="4"
android:stretchMode="columnWidth"
android:gravity="center"
/>
</LinearLayout>


【AndroidManifest.xml】
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ayakix"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="4" />

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".AsyncGridViewActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

</application>
</manifest>

ポイントとなるImageDownloadTask.java内では、画像のダウンロード処理に対して、Handlerを使用しています。このプログラムを作成する前にはAsyncTaskを利用していたのですが、AsyncTaskは同時に処理できるタスク数が標準では5になっているみたいです(プールサイズが5)。そのため、多くの処理を並列に行えないため、Handlerを使いました。