欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

AsyncTask异步下载图片

程序员文章站 2024-01-28 09:12:46
...
这个例子是利用AsyncTask异步下载图片,下载时先将网络图片下载到本地cache目录保存,以imagUrl的图片文件名保存,如果有同名文件在cache目录就从本地加载。

布局文件,先用一个图片占位:

<ImageView
android:id="@+id/image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dip"
android:src="@drawable/product_default_icon" />



private Context context = AsyncTaskDemo.this;
private ImageView image;
//图片地址
private String imageUrl = "http://dl.iteye.com/upload/attachment/0080/1571/2b9a099a-0a7b-3a60-909e-97a8316716cb.jpg";

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.asynctask);
getWidget();
loadImage(imageUrl);
}

/** 获得组件 */
public void getWidget() {
image = (ImageView) findViewById(R.id.image);
}

private void loadImage(final String imageUrl) {
ImageAsyncLoader asyncImageLoader = new ImageAsyncLoader();
// 异步加载图片
Drawable cachedImage = asyncImageLoader.loadDrawable(context, imageUrl, new ImageCallback() {
public void imageLoaded(Drawable imageDrawable, String imageUrl) {
if (imageDrawable != null) {
image.setImageDrawable(ImageAsyncLoader.zoomDrawable(imageDrawable, ImageAsyncLoader.dip2px(context, 150), ImageAsyncLoader.dip2px(context, 150)));
}
}
});
if (cachedImage != null) {image.setImageDrawable(ImageAsyncLoader.zoomDrawable(cachedImage, ImageAsyncLoader.dip2px(context, 150), ImageAsyncLoader.dip2px(context, 150)));
}
}

图片异步加载:

/**
* SoftReference的主要特点是据有较强的引用功能。
* 只有当内存不够的时候,才进行回收这类内存,因此在内存足够的时候,它们通常不被回收。
* 另外,这些引用对象还能保证在Java抛出OutOfMemory 异常之前,被设置为null。
* 它可以用于实现一些常用图片的缓存,实现Cache的功能,保证最大限度的使用内存而不引起OutOfMemory。
*/
private HashMap<String, SoftReference<Drawable>> cacheMap = null;
private BlockingQueue<Runnable> queue = null;
private ThreadPoolExecutor executor = null;

public interface ImageCallback {
public void imageLoaded(Drawable imageDrawable, String imageUrl);
}

public ImageAsyncLoader() {
cacheMap = new HashMap<String, SoftReference<Drawable>>();
/**
* 一个基于已链接节点的、范围任意的 blocking queue。
* 此队列按 FIFO(先进先出)排序元素。
* 队列的头部 是在队列中时间最长的元素。
* 队列的尾部 是在队列中时间最短的元素。
* 新元素插入到队列的尾部,并且队列检索操作会获得位于队列头部的元素。
* 链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。
*/
queue = new LinkedBlockingQueue<Runnable>();
/**
* 线程池维护线程的最少数量2 <br>
* 线程池维护线程的最大数量10<br>
* 线程池维护线程所允许的空闲时间180秒
*/
executor = new ThreadPoolExecutor(2, 10, 180, TimeUnit.SECONDS, queue);
}

public Drawable loadDrawable(final Context context, final String imageUrl, final ImageCallback imageCallback) {
if (cacheMap.containsKey(imageUrl)) {
SoftReference<Drawable> softReference = cacheMap.get(imageUrl);
Drawable drawable = softReference.get();
if (drawable != null) {
return drawable;
}
}

final Handler handler = new Handler() {
public void handleMessage(Message message) {
imageCallback.imageLoaded((Drawable) message.obj, imageUrl);
}
};

// 将任务添加到线程池
executor.execute(new Runnable() {
public void run() {
// 根据URL加载图片
Drawable drawable = loadImageFromUrl(context, imageUrl);

// 图片资源不为空是创建软引用
if (null != drawable)
cacheMap.put(imageUrl, new SoftReference<Drawable>(drawable));

Message message = handler.obtainMessage(0, drawable);
handler.sendMessage(message);
}
});

return null;
}

// 网络图片先下载到本地cache目录保存,以imagUrl的图片文件名保存,如果有同名文件在cache目录就从本地加载
public static Drawable loadImageFromUrl(Context context, String imageUrl) {
Drawable drawable = null;

if (imageUrl == null)
return null;
String fileName = "";

// 获取url中图片的文件名与后缀
if (imageUrl != null && imageUrl.length() != 0) {
fileName = imageUrl.substring(imageUrl.lastIndexOf("/") + 1);
}

// 根据图片的名称创建文件(不存在:创建)
File file = new File(context.getCacheDir(), fileName);

// 如果在缓存中找不到指定图片则下载
if (!file.exists() && !file.isDirectory()) {
try {
// 从网络上下载图片并写入文件
FileOutputStream fos = new FileOutputStream(file);
InputStream is = new URL(imageUrl).openStream();
int data = is.read();
while (data != -1) {
fos.write(data);
data = is.read();
}
fos.close();
is.close();

drawable = Drawable.createFromPath(file.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
// 如果缓存中有则直接使用缓存中的图片
else {
drawable = Drawable.createFromPath(file.toString());
}
return drawable;
}


常用图片处理方法:

/**
* 缩放Drawable
*
* @param drawable
* @param w 缩放后的宽
* @param h 缩放后的高
* @return Drawable
*/
public static Drawable zoomDrawable(Drawable drawable, int w, int h) {
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
// drawable转换成bitmap
Bitmap oldbmp = drawableToBitmap(drawable);
// 创建操作图片用的Matrix对象
Matrix matrix = new Matrix();
// 计算缩放比例
float scaleWidth = ((float) w / width);
float scaleHeight = ((float) h / height);
matrix.postScale(scaleWidth, scaleHeight);
// 设置缩放比例
Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height, matrix, true);
return new BitmapDrawable(newbmp);
}

/**
* 将drawable转换成bitmap
*
* @param drawable
* @return Bitmap
*/
private static Bitmap drawableToBitmap(Drawable drawable) {
// 取drawable的长宽
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; // 取drawable的颜色格式

Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, width, height);
drawable.draw(canvas);
return bitmap;
}

/**
* 单位转换:dip => px
*
* @param ctx 上下文环境
* @param dipValue
* @return
*/
public static int dip2px(Context ctx, int dipValue) {
final float scale = ctx.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale);
}


配置文件:

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