Android开源框架 universal-Image-Loader

本文介绍了Android开发中常用的开源图片加载框架universal-Image-Loader,包括其特性、使用方法和配置,如多线程加载、内存缓存、ListView/GridView加载图片的优化,以及如何处理OutOfMemoryError。同时强调了在特定情况下使用displayImage()方法的优势。
摘要由CSDN通过智能技术生成

universal-Image-Loader

在做安卓开发的时候,肯定会接触到异步夹在图片或者大量加载图片的情况。作为新手肯定会遇到很多问题,如OOM或者图片错误等问题。因此有许多图片加载的开源框架供我们使用,今天学习一下universal-Image-Loader框架。
这个框架的github地址为 https://github.com/nostra13/Android-Universal-Image-Loader。在github上的介绍我们可以看到,该框架支持的URL类型很多,从web、sdcard、contentProvider、assets、drawable等都可以加载图片

"http://site.com/image.png" // from Web
"file:///mnt/sdcard/image.png" // from SD card
"file:///mnt/sdcard/video.mp4" // from SD card (video thumbnail)
"content://media/external/images/media/13" // from content provider
"content://media/external/video/media/13" // from content provider (video thumbnail)
"assets://image.png" // from assets
"drawable://" + R.drawable.img // from drawables (non-9patch images)

另外作者提示我们

Use drawable:// only if you really need it! Always consider the native way to load drawables - ImageView.setImageResource(…) instead of using of ImageLoader.
一般情况下加载drawable文件里面的图片时,都使用setImageResource(…),除非really need universal-Image-Loader时再使用。

universal-Image-Loader的特征

  1. 多线程下载图片,图片可以来源于网络,文件系统,项目文件夹assets中以及drawable中等
  2. 支持随意的配置ImageLoader,例如线程池,图片下载器,内存缓存策略,硬盘缓存策略,图片显示选项以及其他的一些配置
  3. 支持图片的内存缓存,文件系统缓存或者SD卡缓存
  4. 支持图片下载过程的监听
  5. 根据控件(ImageView)的大小对Bitmap进行裁剪,减少Bitmap占用过多的内存
  6. 较好的控制图片的加载过程,例如暂停图片加载,重新开始加载图片,一般使用在ListView,GridView中,滑动过程中暂停加载图片,停止滑动的时候去加载图片
  7. 提供在较慢的网络下对图片进行加载

universal-Image-Loader的使用

要使用这个开源框架,eclipse上需要将这个框架的jar包导入libs文件,并且Add to build path.然后再项目属性里面Order and Export属性里面将这个框架前面的对勾打上。至于Android studio就不知道了,由于电脑较渣,运行太卡。

新建一个MyApplication类,在这里面进行universal-Image-Loader的配置

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        ImageLoaderConfiguration config=ImageLoaderConfiguration.createDefault(this);
        ImageLoader.getInstance().init(config);
    }

}

ImageLoaderConfiguration是ImageLoader的配置参数,在这里直接使用了createDefault()创建了一个默认的,一般默认的就可以了,当然也可以自定义参数,可设置的参数如下

File cacheDir = StorageUtils.getCacheDirectory(context);  
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)  
        .memoryCacheExtraOptions(480, 800) // default = device screen dimensions  
        .diskCacheExtraOptions(480, 800, CompressFormat.JPEG, 75, null)  
        .taskExecutor(...)  
        .taskExecutorForCachedImages(...)  
        .threadPoolSize(3) // default  
        .threadPriority(Thread.NORM_PRIORITY - 1) // default  
        .tasksProcessingOrder(QueueProcessingType.FIFO) // default  
        .denyCacheImageMultipleSizesInMemory()  
        .memoryCache(new LruMemoryCache(2 * 1024 * 1024))  
        .memoryCacheSize(2 * 1024 * 1024)  
        .memoryCacheSizePercentage(13) // default  
        .diskCache(new UnlimitedDiscCache(cacheDir)) // default  
        .diskCacheSize(50 * 1024 * 1024)  
        .diskCacheFileCount(100)  
        .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default  
        .imageDownloader(new BaseImageDownloader(context)) // default  
        .imageDecoder(new BaseImageDecoder()) // default  
        .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default  
        .writeDebugLogs()  
        .build();  

然后调用ImageLoader的init方法将配置的参数传递进去,getInstance方法表明ImageLoader是单例模式。

然后注意配置AndroidManifest.xml文件,将MyApplication配置上,并且加上网络访问和读取外部存储的权限。

开始使用
布局文件,一个ImageView

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

    <ImageView 
        android:id="@+id/third_show_ImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        ></ImageView>

</RelativeLayout>

ImageLoader主要有以下下载图片的方法

这里写图片描述

这里写图片描述

其中loadImageSync方法是同步的。

首先使用loadImage方法

mShowImageView=(ImageView) findViewById(R.id.third_show_ImageView);
        String imageUrl="http://d.hiphotos.baidu.com/baike/w%3D268%3Bg%3D0/sign=abab84ca2af5e0feee188e07645b5395/a8014c086e061d9551cfbceb7cf40ad163d9ca5c.jpg";
        ImageLoader.getInstance().loadImage(imageUrl, new ImageLoadingListener() {

            @Override
            public void onLoadingCancelled(String arg0, View arg1) {

            }

            @Override
            public void onLoadingComplete(String arg0, View arg1, Bitmap arg2) {
                Log.i(TAG, Thread.currentThread().getName()+"--------------");
                mShowImageView.setImageBitmap(arg2);
            }

            @Override
            public void onLoadingFailed(String arg0, View arg1, FailReason arg2) {

            }

            @Override
            public void onLoadingStarted(String arg0, View arg1) {

            }

        });

可以看到,只需要将需要下载的图片的url地址传进去,并且监听图片下载,还可以重写四个方法,对下载开始,下载取消,下载完成,下载失败,分别进行处理。下载完成的三个参数分别为

String imageUri;
View view
Bitmap loadedImage;

如果想简单一点,只对下载完成进行处理

ImageLoader.getInstance().loadImage(imageUrl, new SimpleImageLoadingListener(){
            @Override
            public void onLoadingComplete(String imageUri, View view,
                    Bitmap loadedImage) {
                super.onLoadingComplete(imageUri, view, loadedImage);
                mShowImageView.setImageBitmap(loadedImage);
            }
        });

只需要监听SimpleImageLoadingListener接口就可以了,只需要实现下载完成的方法。

如果需要指定图片的大小,初始化一个ImageSize,设置宽和高,然后调用ImageLoader的另一个重载的方法将size传递进去。

ImageSize size=new ImageSize(200, 200);
        ImageLoader.getInstance().loadImage(imageUrl, size,new SimpleImageLoadingListener(){
            @Override
            public void onLoadingComplete(String imageUri, View view,
                    Bitmap loadedImage) {
                super.onLoadingComplete(imageUri, view, loadedImage);
                mShowImageView.setImageBitmap(loadedImage);
            }
        });

以上只是简单使用,如果需要配置信息
可以配置的信息有

DisplayImageOptions options = new DisplayImageOptions.Builder()  
        .showImageOnLoading(R.drawable.ic_stub) // resource or drawable  
        .showImageForEmptyUri(R.drawable.ic_empty) // resource or drawable  
        .showImageOnFail(R.drawable.ic_error) // resource or drawable  
        .resetViewBeforeLoading(false)  // default  
        .delayBeforeLoading(1000)  
        .cacheInMemory(false) // default  
        .cacheOnDisk(false) // default  
        .preProcessor(...)  
        .postProcessor(...)  
        .extraForDownloader(...)  
        .considerExifParams(false) // default  
        .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default  
        .bitmapConfig(Bitmap.Config.ARGB_8888) // default  
        .decodingOptions(...)  
        .displayer(new SimpleBitmapDisplayer()) // default  
        .handler(new Handler()) // default  
        .build();  

将上面的代码修改一下

ImageSize size=new ImageSize(200, 200);
        //显示图片的配置
        DisplayImageOptions options=new DisplayImageOptions.Builder()
        //使用内存缓存
        .cacheInMemory(true)
        //使用文件缓存
        .cacheOnDisc(true)
        .bitmapConfig(Bitmap.Config.RGB_565)
        .build();
        ImageLoader.getInstance().loadImage(imageUrl, size, options,new SimpleImageLoadingListener(){
            @Override
            public void onLoadingComplete(String imageUri, View view,
                    Bitmap loadedImage) {
                super.onLoadingComplete(imageUri, view, loadedImage);
                mShowImageView.setImageBitmap(loadedImage);
            }
        });

这里配置将图片加载到缓存中,就不需要每次从网络上下载了,但是DisplayImageOptions的一些配置对loadImage是无效的,比如设置下载失败的图片和正在下载的图片等

使用displayImage()方法

修改代码

DisplayImageOptions options2=new DisplayImageOptions.Builder()
        .cacheInMemory(true)
        .cacheOnDisc(true)
        .bitmapConfig(Bitmap.Config.RGB_565)
        .showImageOnLoading(R.drawable.loading_default_small)
        .showImageOnFail(R.drawable.icon_fail)
        .build();

        ImageLoader.getInstance().displayImage(imageUrl, mShowImageView, options2,new SimpleImageLoadingListener(), new ImageLoadingProgressListener() {

            @Override
            public void onProgressUpdate(String imageUrl, View view, int current, int total) {

            }
        });

可以看到使用非常简单,并且它会根据控件的大小和ImageScaleTyle的类型来裁剪图片,而且不需要手动设置bitmap对象,只需要将控件作为参数传递进去就可以了。在我们加载图片的时候,经常需要显示进度,displayImage方法也提供了这样的接口,使用方法上面的代码已经实现了。

加载其他来源的图片

加载文件系统

 String imagePath = "/mnt/sdcard/image.png";  
 String imageUrl = Scheme.FILE.wrap(imagePath); 

加载contentProvider

 String contentprividerUrl = "content://media/external/audio/albumart/13";  

加载assets

String assetsUrl = Scheme.ASSETS.wrap("image.png"); 

加载drawable

String drawableUrl = Scheme.DRAWABLE.wrap("R.drawable.image"); 

可以看到,除了contentProvider外,其他的都是在原地址上使用Scheme进行wrap一下生成新的Url即可。

GirdView,ListView加载图片

而当我们快速滑动GridView,ListView,我们希望能停止图片的加载,而在GridView,ListView停止滑动的时候加载当前界面的图片,这个框架当然也提供这个功能,使用起来也很简单,它提供了PauseOnScrollListener这个类来控制ListView,GridView滑动过程中停止去加载图片,该类使用的是代理模式

listView.setOnScrollListener(new PauseOnScrollListener(imageLoader, pauseOnScroll, pauseOnFling));  
        gridView.setOnScrollListener(new PauseOnScrollListener(imageLoader, pauseOnScroll, pauseOnFling));  

第一个参数就是我们的图片加载对象ImageLoader, 第二个是控制是否在滑动过程中暂停加载图片,如果需要暂停传true就行了,第三个参数控制猛的滑动界面的时候图片是否加载

OutOfMemoryError

虽然这个框架有很好的缓存机制,有效的避免了OOM的产生,一般的情况下产生OOM的概率比较小,但是并不能保证OutOfMemoryError永远不发生,这个框架对于OutOfMemoryError做了简单的catch,保证我们的程序遇到OOM而不被crash掉,但是如果我们使用该框架经常发生OOM,我们应该怎么去改善呢?

  1. 减少线程池中线程的个数,在ImageLoaderConfiguration中的(.threadPoolSize)中配置,推荐配置1-5
  2. 在DisplayImageOptions选项中配置bitmapConfig为Bitmap.Config.RGB_565,因为默认是ARGB_8888, 使用RGB_565会比使用ARGB_8888少消耗2倍的内存
  3. 在ImageLoaderConfiguration中配置图片的内存缓存为memoryCache(new WeakMemoryCache()) 或者不使用内存缓存
  4. 在DisplayImageOptions选项中设置.imageScaleType
    (ImageScaleType.IN_SAMPLE_INT)
    或者imageScaleType(ImageScaleType.EXACTLY)

推荐使用displayImage()

displayImage()方法中,对ImageView对象使用的是Weak references,方便垃圾回收器回收ImageView对象,如果我们要加载固定大小的图片的时候,使用loadImage()方法需要传递一个ImageSize对象,而displayImage()方法会根据ImageView对象的测量值,或者android:layout_width and android:layout_height设定的值,或者android:maxWidth and/or android:maxHeight设定的值来裁剪图片

本文大量参考了xiaanming的博客,博客地址

http://blog.csdn.net/xiaanming/article/details/26810303

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值