Android图片下载机制

来源:互联网 发布:javaweb编程实战宝典 编辑:程序博客网 时间:2024/06/05 03:32

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


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() {@Overridepublic void run() {final Bitmap bitmap = impl.getBitmapFromUrl(url, isCacheToMemory);mHandler.post(new Runnable() {@Overridepublic 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/";@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.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() {@Overridepublic void onClick(View arg0) {mImageLoader.downloadImage(URL, new ImageCallback() {@Overridepublic 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>



0 0
原创粉丝点击