之前写过一篇android异步加载图片类 ,后来接触了一个开源项目universal-image-loader,听说淘宝也是用这玩意
发现自己写的那个异步加载类太简单了,虽然功能是实现了,但是很多优化的问题都没有解决
比如:
同一个ui加载同一张图,会出现只加载一张,其他的加载不了
加载多图的时候会有oom等问题
现在来说说universal-image-loader
特点:
多线程的图像加载
的可能性的宽调谐对ImageLoader的配置(线程池的大小,HTTP选项,内存和光盘高速缓存,显示图像,以及其他)
的图像的可能性中的缓存存储器和/或设备的文件器系统(或SD卡)
可以“听”加载过程中
可自定义每个显示的图像调用分隔的选项
Widget支持
Android 1.5以上支持
使用方法:(我自己封装了一个类ImgConfig使用,方便一些)
只需两步即可加载网络图片:
一、初始化
ImgConfig.initImageLoader();
二、
ImgConfig.showUserSImg(imgUrl, imageview); //图片的url,要显示的view
以下是我自己写的ImgConfig,仅供参考:
public class ImgConfig extends ImageLoader { private static DisplayImageOptions options_corner; private static DisplayImageOptions options_square; private static AnimateFirstDisplayListener animateFirstDisplayListener = new AnimateFirstDisplayListener(); /** * @param url 服务器的文件名 * @param imageView * 显示方形图片 S for Square */ public static void showUserSImg(String url, ImageView imageView) { ImageLoader.getInstance().displayImage(url, imageView, options_square, animateFirstDisplayListener); } /** * @param url 服务器的文件名 * @param imageView * 圆角 C for Corner */ public static void showUserCImg(String url, ImageView imageView) { ImageLoader.getInstance().displayImage(url, imageView, options_corner, animateFirstDisplayListener); } /** * 初始化图片读取方式 */ public static void initImageLoader() { DisplayImageOptions options_corner = new DisplayImageOptions.Builder() .showImageOnLoading(ImgHandler.ToCircular(R.drawable.defult_head)) // 加载中 .showImageForEmptyUri(ImgHandler.ToCircular(R.drawable.defult_head)) // 空uri .showImageOnFail(ImgHandler.ToCircular(R.drawable.defult_head)) // 失败时 .cacheInMemory(true) // 设置下载的图片是否缓存在内存中 .cacheOnDisc(true) // 设置下载的图片是否缓存在SD卡中 .considerExifParams(true) .displayer(new RoundedBitmapDisplayer(10)) // 展现方式:圆角 .resetViewBeforeLoading(true) .imageScaleType(ImageScaleType.EXACTLY) // new FadeInBitmapDisplayer(300) 渐现 .build(); options_square = new DisplayImageOptions.Builder() .showImageOnLoading(R.drawable.defult_head) .showImageForEmptyUri(R.drawable.defult_head) .showImageOnFail(R.drawable.defult_head) .cacheInMemory(true) .cacheOnDisc(true) .considerExifParams(true) .displayer(new FadeInBitmapDisplayer(100)) // 展现方式:渐现 .resetViewBeforeLoading(true) .imageScaleType(ImageScaleType.EXACTLY) .build(); // This configuration tuning is custom. You can tune every option, you // may tune some of them, // or you can create default configuration by // ImageLoaderConfiguration.createDefault(this); // method. ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder( ContextUtil.getInstance()) .threadPriority(Thread.NORM_PRIORITY) //线程池的数量 .denyCacheImageMultipleSizesInMemory() // 不同大小图片只有一个缓存,默认多个 .tasksProcessingOrder(QueueProcessingType.LIFO) // 设置图片下载和显示的工作队列排序 .discCache(new LimitedAgeDiscCache(new File(Constant.SAVE_IMG_PATH), new Md5FileNameGenerator(), 7 * 24 * 60 * 60)) // 7天自动清除,按秒算 // .writeDebugLogs() // Remove for release app .imageDownloader( //或许你的服务器有特定的加载图的方式,在这里实现 new BaseImageDownloader(ContextUtil.getInstance()) { @Override public InputStream getStream(String imageUri, Object extra) throws IOException { return super.getStream(imageUri, extra); } @Override protected InputStream getStreamFromNetwork( String imageUri, Object extra) throws IOException { HttpURLConnection conn = createConnection( imageUri, extra); int redirectCount = 0; while (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) { conn = createConnection( conn.getHeaderField("Location"), extra); redirectCount++; } InputStream imageStream = null; try { imageStream = conn.getInputStream(); } catch (IOException e) { // Read all data to allow reuse connection // (http://bit.ly/1ad35PY) IoUtils.readAndCloseStream(conn .getErrorStream()); } return new ContentLengthInputStream( new BufferedInputStream(imageStream, BUFFER_SIZE), conn .getContentLength()); } }).build(); // Initialize ImageLoader with configuration. 初始化 ImageLoader.getInstance().init(config); } /** * @author Administrator 监听读取完图片 */ private static class AnimateFirstDisplayListener extends SimpleImageLoadingListener { // 放到内存 static final List<String> displayedImages = Collections .synchronizedList(new LinkedList<String>()); @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { if (loadedImage != null) { ImageView imageView = (ImageView) view; boolean firstDisplay = !displayedImages.contains(imageUri); if (firstDisplay) { FadeInBitmapDisplayer.animate(imageView, 500); displayedImages.add(imageUri); } } } } }
特别提示以下 .disCache() 和 .imageDownloader
因为我不想要自动帮我加密文件,所以我.disCache() 里面的加密方法 new Md5FileNameGenerator()
换成了
new FileNameGenerator() { @Override public String generate(String imageUri) { return FileUtil.getFileName(imageUri); } }
服务器有自己的加载方式,我把加载.imageDownloader的加载图片方法换了
new BaseImageDownloader(ContextUtil.getInstance()) { @Override public InputStream getStream(String imageUri, Object extra) throws IOException { return super.getStream(imageUri, extra); } @Override protected InputStream getStreamFromNetwork( String imageUri, Object extra) throws IOException { HttpURLConnection conn = createConnection( imageUri, extra); int redirectCount = 0; while (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) { conn = createConnection( conn.getHeaderField("Location"), extra); redirectCount++; } InputStream imageStream = null; try { imageStream = conn.getInputStream(); } catch (IOException e) { // Read all data to allow reuse connection // (http://bit.ly/1ad35PY) IoUtils.readAndCloseStream(conn .getErrorStream()); } return new ContentLengthInputStream( new BufferedInputStream(imageStream, BUFFER_SIZE), conn .getContentLength()); } }
总结: universal-image-loader 这个开源项目很好用,
研究了一下源码,有很多启发,扩展性很好,值得我们学习
官方提供的例子: universal-image-loader例子