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>
相关文章推荐
- Android媒体库更新问题
- Android如何高效显示较大的Bitmaps
- android打包签名介绍
- 你需要知道的Android拍照适配方案
- Android Studio教程 简介与入门(资料比较旧,但有一定参考价值)
- Android统计APK方法数
- RxJava在Android中内存泄漏解决以及RxJava的封装
- Android中HorizontalScrollView使用方法详解
- Android 百分比布局库(percent-support-lib) 解析与扩展
- android 控件 折叠toolbar-CollapsingToolbarLayout
- Android ScrollView和ListView滑动冲突问题
- Android activity的生命周期
- android的ColorStateList简单使用
- Android 使用Retrofit2问题汇总
- Android学习系列(18)--App数据格式之解析Json
- 提高效率的 Android Studio快捷键 技巧汇总
- android design
- android自定义viewGroup 不显示问题
- Android Studio教程 基本设置与运行
- Android studio创建第一个app