背景:在上一篇中,主要介绍了内存缓存封装类和SD卡上临时文件缓存封装类,这一篇中,我们来封装一下 从网络获取图片的工具类及异步加载图片类
1、从网络获取图片的工具类:ImageHttpUtil.java
package com.ice.android.common.util.imagecache;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
/**
* 从网络获取图片工具类
* @author ice
*/
public class ImageHttpUtil {
private static final String TAG = "ImageHttpUtil";
/**
* 请求网络 根据图片url从网络上获取图片
* 这里使用 apache的 HttpClient请求网络
* @param mImageParams
* @return
*/
public static Bitmap getImageData(String url){
HttpGet getRequest = new HttpGet(url);
try {
HttpResponse response = new DefaultHttpClient().execute(getRequest);
int statusCode = response.getStatusLine().getStatusCode();
if(statusCode != HttpStatus.SC_OK){
Log.w(TAG, "Error: "+statusCode+" while retrieving bitmap from "+url);
return null;
}
HttpEntity entity = response.getEntity();
if(entity != null){
InputStream inputStream = null;
try {
inputStream = entity.getContent();
/* return BitmapFactory.decodeStream(inputStream); // Bug on slow connections, fixed in future release. */
FlushedInputStream fis = new FlushedInputStream(inputStream);
return BitmapFactory.decodeStream(fis);
} catch (IllegalStateException e) {
e.printStackTrace();
}finally{
if(inputStream != null){
inputStream.close();
}
entity.consumeContent();
}
}
} catch (ClientProtocolException e) {
getRequest.abort(); // 中断请求
Log.w(TAG, "Error: "+e.getMessage()+" while retrieving bitmap from "+url);
e.printStackTrace();
} catch (IOException e) {
getRequest.abort(); // 中断请求
Log.w(TAG, "I/O Error: "+e.getMessage()+" while retrieving bitmap from "+url);
e.printStackTrace();
}
return null;
}
/**
* 继承 FilterInputStream <过滤的输入流>
* 能过滤掉/跳过输入流中的某些字节
* @author ice
*
*/
private static class FlushedInputStream extends FilterInputStream {
public FlushedInputStream(InputStream inputStream) {
super(inputStream);
}
/**
* 重写 skip() 方法
* 跳过和丢弃此输入流中数据的 n个字节,完成输入流的字节过滤
*/
@Override
public long skip(long n) throws IOException {
long totalBytesSkipped = 0L;
while (totalBytesSkipped < n) {
long bytesSkipped = in.skip(n - totalBytesSkipped);
if (bytesSkipped == 0L) {
int b = read();
if (b < 0) {
break; // we reached EOF
} else {
bytesSkipped = 1; // we read one byte
}
}
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}
}
package com.ice.android.common.util.imagecache;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
/**
* 异步加载图片缓存 类
* 单例模式
* @author ice
*
*/
public class AsynImageLoader {
private static final String TAG = "AsynImageLoader";
/** 线程池数量 */
private static final int THREAD_NUM = 3;
/** 线程池 */
private ExecutorService executorService;
/** 内存缓存对象 */
private ImageMemCache memCache;
/** sd卡 文件缓存对象 */
private ImageFileCache fileCache;
private static AsynImageLoader instance;
/**
* 单例模式
* @param memCache
* @param fileCache
*/
private AsynImageLoader() {
executorService = Executors.newFixedThreadPool(THREAD_NUM);
this.memCache = new ImageMemCache();
this.fileCache = new ImageFileCache();
}
/**
* 获取实例
* @return
*/
public static synchronized AsynImageLoader getInstance(){
if(instance == null){
instance = new AsynImageLoader();
}
return instance;
}
/**
* 加载图片数据
* @param mImageParams
* @param mHandler
*/
public void loadImageData(ImageParams mImageParams,Handler mHandler){
executorService.submit(new ImgLoadTask(mImageParams,mHandler));
}
/**
* 从网络上获取图片数据,并将图片缓存到内存或是sdcard上
* @param imageParams
* @return
*/
private Bitmap loadNetImage(ImageParams imageParams){
Bitmap imageData = ImageHttpUtil.getImageData(imageParams.getUrl().trim());
if(imageData != null){
memCache.addBitmapToCache(imageParams, imageData);
fileCache.addBitmapToSdcard(imageParams, imageData);
}else{
Log.d(TAG, "获取网络图片数据失败,url = "+imageParams.getUrl());
}
return imageData;
}
/**
* 从本地缓存中获取图片数据
* 获得一个图片的数据,从三个地方获取,首先是内存缓存,然后是文件(sdcard)缓存,最后从网络获取
* @param imageParams
* @return
*/
public Bitmap loadCacheImage(ImageParams imageParams){
Bitmap imageData = null;
// 从内存缓存中获取图片
imageData = memCache.getImageData(imageParams);
if(imageData == null){
// 从文件(sdcard)缓存中获取图片
imageData = fileCache.getImageData(imageParams);
}
return imageData;
}
/**
* 图片加载子线程任务 内部类
* @author ice
*
* java.util.concurrent.Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。
* 但是 Runnable 不会返回结果
*
*/
private class ImgLoadTask implements Callable<Void>{
private ImageParams imageParams;
private Handler handler;
public ImgLoadTask(ImageParams mImageParams, Handler mHandler) {
this.imageParams = mImageParams;
this.handler = mHandler;
}
@Override
public Void call() throws Exception {
Message msg = new Message();
msg.obj = loadNetImage(imageParams);
if(msg.obj != null){
// 将加载得到的图片对象 通过Message承载发送给Handler处理
handler.sendMessage(msg);
}
return null;
}
}
}
ok ! 到这里关于App应用开发中 有关图片缓存问题的代码已封装完毕!
小吕, 初转Android开发 算是Android新人,愿与大家共同学习!