您的位置:首页 > 移动开发 > Android开发

Android图片下载机制

2016-05-23 16:12 337 查看


以上是一次图片下载的全过程

ImageLoader类的内部封装了一个线程池,因为图片下载需要开启一个子线程,大量的图片下载导致大量的线程创建和销毁显然是不可取的,采用线程池可以提高效率并且节省CPU的调度带来的消耗。

<span style="font-size:18px;">public class ImageLoader {

private static HashSet<String> mImageUrlSet;

private static Map<String,SoftReference<Bitmap>> mImageCache;

private static LoaderImpl impl;

private static ExecutorService mExecutorService;

private Handler mHandler;

/**
* 异步加载的回调接口
*/
public interface ImageCallback{
public void onImageCallback(Bitmap bitmap, String imageUrl);
}

static{
mImageUrlSet = new HashSet<String>();
mImageCache = new HashMap<String, SoftReference<Bitmap>>();
impl = new LoaderImpl(mImageCache);
}

public ImageLoader(Context context){
mHandler = new Handler();
startThreadPoolIfNecessary();

String defaultDir = context.getCacheDir().getAbsolutePath();
setCacheDir(defaultDir);
}

/**
* 是否缓存到文件
* @param flag
*/
public void setCache2File(boolean flag){
impl.setCache2File(flag);
}

/**
* 设置缓存文件路径
* @param path
*/
public void setCacheDir(String path){
impl.setCacheDir(path);
}

//开启线程池
public static void startThreadPoolIfNecessary(){
if(mExecutorService == null || mExecutorService.isShutdown() || mExecutorService.isTerminated()){
mExecutorService = Executors.newFixedThreadPool(5);//创建大小为5的线程池
}
}

/**
* 异步下载图片,并缓存到内存中
* @param url
* @param callback
*/
public void downloadImage(final String url, final ImageCallback callback){
downloadImage(url, true, callback);
}

/**
* 异步下载图片,并缓存到内存中
* @param cache2Memory 是否缓存到内存中
* @param url
* @param callback
*/
public void downloadImage(final String url, final Boolean isCacheToMemory, final ImageCallback callback){
//如果下载列表中已经存在该url,就返回,防止重复下载
if(mImageUrlSet.contains(url)){
return;
}

//先从缓存中取图片(先内存再文件)
Bitmap bitmap = impl.getBitmapFromMemory(url);
//缓存中有对应图片就展示图片
if(bitmap!= null){
if(callback != null){
callback.onImageCallback(bitmap, url);
}
} else {
//缓存中没有图片就从网络下载图片
mImageUrlSet.add(url);
mExecutorService.execute(new Runnable() {
@Override
public void run() {

final Bitmap bitmap = impl.getBitmapFromUrl(url, isCacheToMemory);
mHandler.post(new Runnable() {
@Override
public void run() {

if(callback != null){
callback.onImageCallback(bitmap, url);
mImageUrlSet.remove(url);
}

}
});
}
});
}
}

}</span>


LoaderImpl类封装了从网络下载图片的方法、存储缓存的方法、读取缓存的方法、获取MD5值的方法。

因为图片的存储是以Map的形式存储的,key就是url,value就是bitmap,但是url可能包含复杂的字符,所以采用转换成MD5值的方式获取到唯一的key。

<span style="font-size:18px;">public class LoaderImpl {

//内存中的软引用缓存
private Map<String,SoftReference<Bitmap>> imageCache;
//是否缓存图片到本地文件
private boolean cache2FileFlag = false;
//缓存目录,默认/data/data/package/cache/路径
private String cacheDir;

public LoaderImpl(Map<String,SoftReference<Bitmap>> imageCache){
this.imageCache = imageCache;
}

public void setCache2File(boolean flag){
cache2FileFlag = flag;
}

public void setCacheDir(String path){
cacheDir = path;
}

/**
* 下载图片
* @param url 图片URL地址
* @param isCacheToMemory 是否缓存
* @param bitmap 图片bitmap对象
*/
public Bitmap getBitmapFromUrl(String url, boolean isCacheToMemory){
Bitmap bitmap = null;
try {
URL mUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) mUrl.openConnection();
InputStream in = conn.getInputStream();
bitmap = BitmapFactory.decodeStream(in);

if(isCacheToMemory){
//先缓存到内存中
imageCache.put(url, new SoftReference<Bitmap>(bitmap));
if(cache2FileFlag){
//缓存到文件中
String fileName = getMD5Code(url);
String filePath = this.cacheDir + "/" + fileName;
FileOutputStream fos = new FileOutputStream(filePath);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
}
}

in.close();
conn.disconnect();
return bitmap;

} catch (Exception e) {
return null;
}
}

/**
* 从内存中获取bitmap
* @param url
*/
public Bitmap getBitmapFromMemory(String url){
Bitmap bitmap = null;
if(imageCache.containsKey(url)){
synchronized (imageCache) {
SoftReference<Bitmap> bitmapRef = imageCache.get(url);
//从内存中获取图片成功就返回bitmap对象
if(bitmapRef != null){
bitmap = bitmapRef.get();
return bitmap;
}
}
}
//内存获取图片不成功就从文件中读取
if(cache2FileFlag){
bitmap = getBitmapFromFile(url);
if(bitmap != null){
imageCache.put(url, new SoftReference<Bitmap>(bitmap));
}
}

return bitmap;
}

/**
* 从文件中获取bitmap
* @param url
*/
private Bitmap getBitmapFromFile(String url){
Bitmap bitmap = null;
String fileName = getMD5Code(url);
if(fileName == null){
return null;
}

String filePath = cacheDir + "/" + fileName;

try {
FileInputStream fis = new FileInputStream(filePath);
bitmap = BitmapFactory.decodeStream(fis);
} catch (Exception e) {
e.printStackTrace();
bitmap = null;
}

return bitmap;
}

private static String getMD5Code(String str){
MessageDigest messageDigest = null;
try {
messageDigest = MessageDigest.getInstance("MD5");
messageDigest.reset();
messageDigest.update(str.getBytes("UTF-8"));
} catch (Exception e) {
e.printStackTrace();
return null;
}

byte[] byteArray = messageDigest.digest();
StringBuffer md5StrBuff = new StringBuffer();
for(int i = 0; i<byteArray.length; i++){
if(Integer.toHexString(0xFF & byteArray[i]).length() == 1){
md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));
} else {
md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
}
}

return md5StrBuff.toString();
}

}</span>


最后是Activity的代码以及XML布局文件的代码
public class ImageShowActivity extends Activity{

private TextView mTvDownload;
private ImageView mIvShow;
//这个是想去App的一个图片链接
private final static String URL = "http://xqproduct.xiangqu.com/Fpv7zJ0IV4P85c9_id0uhfZ4W-mB?imageView2/2/w/320/q/100/format/webp/750x750/";

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image);
mTvDownload = (TextView) findViewById(R.id.download);
mIvShow = (ImageView) findViewById(R.id.image);

final ImageLoader mImageLoader = new ImageLoader(getApplicationContext());
mImageLoader.setCacheDir(this.getCacheDir().getAbsolutePath());
Log.d("ggg", this.getCacheDir().getAbsolutePath());
mImageLoader.setCache2File(true);

mTvDownload.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {

mImageLoader.downloadImage(URL, new ImageCallback() {

@Override
public void onImageCallback(Bitmap bitmap, String imageUrl) {

if(bitmap != null){
mIvShow.setImageBitmap(bitmap);
} else {

}
}
});
}
});

}

}


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<TextView
android:id="@+id/download"
android:layout_width="match_parent"
android:layout_height="44dp"
android:gravity="center"
android:text="download" />

<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#ff444444"/>

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >

<ImageView
android:id="@+id/image"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_centerInParent="true"
android:scaleType="centerCrop" />

</RelativeLayout>

</LinearLayout>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: