图片显示框架(二)

本文详细介绍了Android平台上的两款流行图像加载库:Android-Universal-Image-Loader与Glide。内容涵盖配置方法、使用技巧及注意事项等,帮助开发者更好地理解和应用这些库。
摘要由CSDN通过智能技术生成

框架详解

Android-Universal-Image-Loader

一、特点
多线程的图像加载
ImageLoader的配置(线程池的大小,HTTP选项,内存和光盘高速缓存,显示图像,以及其他)
缓存存储器和/或设备的文件器系统(或SD卡)
可以“听”加载过程中
可自定义每个显示的图像调用分隔的选项
Widget支持
Android 1.5以上支持

二、使用方法
1.设置缓存目录(希望的缓存文件的目录:imageloader/Cache)
File cacheDir = StorageUtils.getOwnCacheDirectory(getApplicationContext(), "imageloader/Cache"); 
之后在ImageLoaderConfiguration的配置文件中通过设置
.discCache(new UnlimitedDiscCache(cacheDir))//自定义缓存路径  

2.配置ImageLoaderConfiguration(最好放在Application里面)
ImageLoaderConfiguration config = new ImageLoaderConfiguration  
.Builder(context)  
.memoryCacheExtraOptions(480, 800) // max width, max height,即保存的每个缓存文件的最大长宽  
.discCacheExtraOptions(480, 800, CompressFormat.JPEG, 75, null) // Can slow ImageLoader, use it carefully (Better don't use it)/设置缓存的详细信息,最好不要设置这个  
.threadPoolSize(3)//线程池内加载的数量  
.threadPriority(Thread.NORM_PRIORITY - 2)  
.denyCacheImageMultipleSizesInMemory()  
.memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024)) // You can pass your own memory cache implementation/你可以通过自己的内存缓存实现       
.memoryCacheSize(2 * 1024 * 1024)    
.discCacheSize(50 * 1024 * 1024)    
.discCacheFileNameGenerator(new Md5FileNameGenerator())//将保存的时候的URI名称用MD5 加密  
.tasksProcessingOrder(QueueProcessingType.LIFO)  
.discCacheFileCount(100) //缓存的文件数量  
.discCache(new UnlimitedDiscCache(cacheDir))//自定义缓存路径  
.defaultDisplayImageOptions(DisplayImageOptions.createSimple())  
.imageDownloader(new BaseImageDownloader(context, 5 * 1000, 30 * 1000)) // connectTimeout (5 s), readTimeout (30 s)超时时间  
.writeDebugLogs() // Remove for release app  
.build();//开始构建  

最后调用ImageLoader.getInstance().init(config);//全局初始化此配置 


3.得到实例化对象并设置参数
protected ImageLoader imageLoader = ImageLoader.getInstance();
DisplayImageOptions 的设置:
DisplayImageOptions options;  
options = new DisplayImageOptions.Builder()  
 .showImageOnLoading(R.drawable.ic_launcher) //设置图片在下载期间显示的图片  
 .showImageForEmptyUri(R.drawable.ic_launcher)//设置图片Uri为空或是错误的时候显示的图片  
.showImageOnFail(R.drawable.ic_launcher)  //设置图片加载/解码过程中错误时候显示的图片
.cacheInMemory(true)//设置下载的图片是否缓存在内存中  
.cacheOnDisc(true)//设置下载的图片是否缓存在SD卡中  
.considerExifParams(true)  //是否考虑JPEG图像EXIF参数(旋转,翻转)
.imageScaleType(ImageScaleType.EXACTLY_STRETCHED)//设置图片以如何的编码方式显示  
.bitmapConfig(Bitmap.Config.RGB_565)//设置图片的解码类型//  
.decodingOptions(android.graphics.BitmapFactory.Options decodingOptions)//设置图片的解码配置  
//.delayBeforeLoading(int delayInMillis)//int delayInMillis为你设置的下载前的延迟时间
//设置图片加入缓存前,对bitmap进行设置  
//.preProcessor(BitmapProcessor preProcessor)  
.resetViewBeforeLoading(true)//设置图片在下载前是否重置,复位  
.displayer(new RoundedBitmapDisplayer(20))//是否设置为圆角,弧度为多少  
.displayer(new FadeInBitmapDisplayer(100))//是否图片加载好后渐入的动画时间  
.build();//构建完成  

注:
  以上配置中的:
 1).imageScaleType(ImageScaleType imageScaleType)  是设置 图片的缩放方式
 缩放类型mageScaleType:
          EXACTLY :图像将完全按比例缩小的目标大小
          EXACTLY_STRETCHED:图片会缩放到目标大小完全
          IN_SAMPLE_INT:图像将被二次采样的整数倍
          IN_SAMPLE_POWER_OF_2:图片将降低2倍,直到下一减少步骤,使图像更小的目标大小
          NONE:图片不会调整
 2).displayer(BitmapDisplayer displayer)   是设置 图片的显示方式
  显示方式displayer:
          RoundedBitmapDisplayer(int roundPixels)设置圆角图片
          FakeBitmapDisplayer()这个类什么都没做
          FadeInBitmapDisplayer(int durationMillis)设置图片渐显的时
          SimpleBitmapDisplayer()正常显示一张图片


4.显示调用方法
ImageLoader.getInstance().displayImage(imageUrl, imageView); // imageUrl代表图片的URL地址,imageView代表承载图片的IMAGEVIEW控件
ImageLoader.getInstance().displayImage(imageUrl, imageView,options); // imageUrl代表图片的URL地址,imageView代表承载图片的  

5.监听方法
①图片加载时候带加载情况的监听

  方法:
 public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,ImageLoadingListener listener) {}
  ImageLoadingListener 用于监听图片的下载情况。


  具体实现
imageLoader.displayImage(imageUrl, imageView, options, new ImageLoadingListener() {  
    @Override  
    public void onLoadingStarted() {  
       //开始加载的时候执行  
    }  
    @Override  
    public void onLoadingFailed(FailReason failReason) {        
       //加载失败的时候执行  
    }   
    @Override   
    public void onLoadingComplete(Bitmap loadedImage) {  
       //加载成功的时候执行  
    }   
    @Override   
    public void onLoadingCancelled() {  
       //加载取消的时候执行  

    }});  

②图片加载时候,带监听又带加载进度条的情况
   调用:
public void loadImage(String uri, ImageSize targetImageSize, DisplayImageOptions options,
                    ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {}


   具体实现:
imageLoader.displayImage(imageUrl, imageView, options, new ImageLoadingListener() {  
    @Override  
    public void onLoadingStarted() {  
       //开始加载的时候执行  
    }  
    @Override  
    public void onLoadingFailed(FailReason failReason) {        
       //加载失败的时候执行  
    }      
    @Override      
    public void onLoadingComplete(Bitmap loadedImage) {  
       //加载成功的时候执行  
    }      
    @Override      
    public void onLoadingCancelled() {  
       //加载取消的时候执行  
    },new ImageLoadingProgressListener() {        
      @Override  
      public void onProgressUpdate(String imageUri, View view, int current,int total) {     
      //在这里更新 ProgressBar的进度信息  
      }  
    });  


6.注意事项
注意事项
  1.上述提到的2个权限必须加入,否则会出错
<uses-permission android:name="android.permission.INTERNET" />  
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  2.ImageLoaderConfiguration必须配置并且全局化的初始化这个配置ImageLoader.getInstance().init(config);  否则也会出现错误提示
  3.ImageLoader是根据ImageView的height,width确定图片的宽高。
  4.如果经常出现OOM
   ①减少配置之中线程池的大小,(.threadPoolSize).推荐1-5;
   ②使用.bitmapConfig(Bitmap.config.RGB_565)代替ARGB_8888;
   ③使用.imageScaleType(ImageScaleType.IN_SAMPLE_INT)或者        try.imageScaleType(ImageScaleType.EXACTLY);
   ④避免使用RoundedBitmapDisplayer.他会创建新的ARGB_8888格式的Bitmap对象;
   ⑤使用.memoryCache(new WeakMemoryCache()),不要使用.cacheInMemory();

String imageUri = "http://site.com/image.png"; // from Web  
String imageUri = "file:///mnt/sdcard/image.png"; // from SD card  
String imageUri = "content://media/external/audio/albumart/13"; // from content provider  
String imageUri = "assets://image.png"; // from assets  
String imageUri = "drawable://" + R.drawable.image; // from drawables (only images, non-9patch)  

Picasso(不再详解一般用Glide)

Glide

一、集成

1.项目中集成Glide 
在gradle中添加Glide库:

dependencies {
    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'com.android.support:appcompat-v7:23.1.1'
}
Glide的集成离不开v4包,所以必须添加support包。 
2.Glide集成其他库 
Glide包含一些小的、可选的集成库,目前Glide集成库当中包含了访问网络操作的Volley和OkHttp: 
(1)Volley集成 
第一步、添加依赖

dependencies {
    compile 'com.github.bumptech.glide:volley-integration:1.2.2'
    compile 'com.mcxiaoke.volley:library:1.0.5'
}

第二步、创建Volley集成库的GlideModule

<meta-data
 android:name="com.bumptech.glide.integration.volley.VolleyGlideModule"
    android:value="GlideModule" />

然后改变混淆文件:

-keep class com.bumptech.glide.integration.volley.VolleyGlideModule
#or
-keep public class * implements com.bumptech.glide.module.GlideModule
(2)OkHttp集成 
第一步、添加依赖

dependencies {
    compile 'com.github.bumptech.glide:okhttp-integration:1.2.2'
    compile 'com.squareup.okhttp:okhttp:2.0.0'
}


然后改变混淆文件:

-keep class com.bumptech.glide.integration.okhttp.OkHttpGlideModule
#or
-keep public class * implements com.bumptech.glide.module.GlideModule

(3)集成转换器(此处只介绍集成库,使用后面再讲) 
第一步、gradle添加依赖

repositories {
    jcenter()
    mavenCentral()  // GPUImage for Android
}

dependencies {
    compile 'jp.wasabeef:glide-transformations:2.0.1'
    // If you want to use the GPU Filters
    compile 'jp.co.cyberagent.android.gpuimage:gpuimage-library:1.3.0'
}

通过这个转换器库,可以实现各式各样的图片,非常强大。


二、Glide配置 

1.第一步:
public class GlideModelConfig implements GlideModule {

    int diskSize = 1024 * 1024 * 100;
    int memorySize = (int) (Runtime.getRuntime().maxMemory()) / 8;  // 取1/8最大内存作为最大缓存

    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        // 定义缓存大小和位置
        builder.setDiskCache(new InternalCacheDiskCacheFactory(context, diskSize));  //内存中
        builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, "cache", diskSize)); //sd卡中

        // 默认内存和图片池大小
        MemorySizeCalculator calculator = new MemorySizeCalculator(context);
        int defaultMemoryCacheSize = calculator.getMemoryCacheSize(); // 默认内存大小
        int defaultBitmapPoolSize = calculator.getBitmapPoolSize(); // 默认图片池大小
        builder.setMemoryCache(new LruResourceCache(defaultMemoryCacheSize)); // 该两句无需设置,是默认的
        builder.setBitmapPool(new LruBitmapPool(defaultBitmapPoolSize));

        // 自定义内存和图片池大小
        builder.setMemoryCache(new LruResourceCache(memorySize));
        builder.setBitmapPool(new LruBitmapPool(memorySize));

        // 定义图片格式
        builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
        builder.setDecodeFormat(DecodeFormat.PREFER_RGB_565); // 默认
    }

    @Override
    public void registerComponents(Context context, Glide glide) {
    }
}

2.第二步: 
这GlideModel可以在AndroidManifest.xml文件中注册,以便Glide能够找到你的Module

<meta-data
            android:name="com.example.sun.glidedemo.GlideModelConfig"
            android:value="GlideModule" />

3.第三步: 
将上面的实现了加入到proguard.cfg当中,代码混淆:

-keepnames class * com.example.jianglei.glidedemo.GlideModelConfig

可能遇到的问题: 
Glide允许一个应用当中存在多个GlideModules,但是Glide并不会按照一个特殊的顺序去调用已注册的GlideModules,如果一个应用的多个依赖工程当中有多个相同的Modules,就有可能会产生冲突。 
如果一个冲突是不可避免的,应用应该默认去定义一个自己的Module,用来手动地处理这个冲突,在进行Manifest合并的时候,可以用下面的标签排除冲突的Module:

<meta-data android:name=”com.example.sun.glidedemo.GlideModelConfig” tools:node=”remove”/>


三、Glide使用详情

1.基本使用:
Glide.with(context)  
    .load("xxxx.png")  
    .into(imageView);

Glide的with()可以接受的类型有如下:
Context context;
Activity activity;
FragmentActivity fragmentActivity;
Fragment fragment;

load()是加载目标资源,可以接受的参数类型有如下:
Uri uri;
String uriString;
File file;
Integer resourceId;
byte[] model;
String model;

into()就是加载资源完成后作什么处理,它接受三种参数:
// 显示在控件上
into(ImageView imageView);
// 通过回调获得加载结果,可能在项目中,一个图片在多个地方使用,可以在回调中获得该图片的Bitmap操作
into(Target target);
Glide.with(mContext).load(url).asBitmap().into(new SimpleTarget<Bitmap>() {
            @Override
            public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) {
                image.setImageBitmap(resource);
            }
        });
Glide.with(mContext).load(url).asBitmap().into(new Target<Bitmap>() {
            @Override
            public void onLoadStarted(Drawable placeholder) {
                // 设置加载过程中的Drawable
            }

            @Override
            public void onLoadFailed(Exception e, Drawable errorDrawable) {
                // 设置加载失败的Drawable
            }

            @Override
            public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
                // 设置加载成功的Bitmap
            }

            @Override
            public void onLoadCleared(Drawable placeholder) {
                // 设置加载被取消时的Drawable
            }

            @Override
            public void getSize(SizeReadyCallback cb) {}

            @Override
            public void setRequest(Request request) {}

            @Override
            public Request getRequest() {
                return null;
            }

            @Override
            public void onStart() {}

            @Override
            public void onStop() {}

            @Override
            public void onDestroy() {}
        });

// 指定期望的图片大小,返回一个Bitmap对象,要在子线程中获取,我觉得这个可以在应用使用,比如在主页我需要显示这个图片,我可以在欢迎页面加载这个图片,到了主页可以直接使用,至于为何要在线程中使用,有待研究。
into(int w, int h);
new Thread(new Runnable() {
        @Override
        public void run() {
            Bitmap bitmap = Glide.with(context)  
                .load(url)  
                .into(200, 200)
                .get();
        }
    }).start();

除了with(),load(),into()三个基本的方法,Glide还有很多使用的Api,下面一一道来。 

2.设置bitmap或者gif
.asBitmap();
.asGif();
这两句话,有时候不设置是可以的,但是有时候配合其他属性一起设置的时候,如果没有这个属性的话,其他属性无法实现,所以大家还是规范一些,写完整些。

3.设置图片大小
.override(int w, int h); 
指定加载bitmap的大小,比如原图是500 x 500,into(100, 100),加载出的bitmap就是100 x 100,这样就可以适配各种所需的UI大小,Glide已经为你做好了比例缩放,经过我的试验,如果图片是720 x 1280,将其设置成720 x 500,该图片将会以500这个尺寸比例缩放。
Glide.with(this).load(R.mipmap.login).asBitmap().override(720, 500).into(imageView);

4.加载缩略图
thumbnail(0.1f);
它是在你into的view中先加载设置的缩略图,然后才会加载大图,注:参数范围为0~1。

5.设置占位图或者加载错误图:
.placeholder(R.drawable.placeholder)  
.error(R.drawable.imagenotfound) 
在实际项目中,为了优化显示,比如头像在下载过程中,会使用一张默认的图片先在UI上面显示,则用placeholder,若加载成功,则显示下载图片,否则就显示加载失败的图片,使用error。

6.加载完成动画
.animate(Animator animator);//或者int animationId 
初次加载出Bitmap时展示的动画,可以是属性动画,也可以是Tween动画,可以是加载代码动画,也可以是动画资源文件,方便的很。 
注:这个动画只在初次加载出来时使用,已经加载过了,下载再从缓存中取是不会动画的。

7.图片适配scaleType
.centerCrop(); // 长的一边撑满
.fitCenter(); // 短的一边撑满

8.暂停\回复请求
Glide.with(context).resumeRequests(); 
Glide.with(context).pauseRequests(); 
当列表在滑动的时候,调用pauseRequests()取消请求,滑动停止时,调用resumeRequests()恢复请求。

9.在后台线程当中进行加载和缓存
downloadOnly(int width, int height)
downloadOnly(Y target)// Y extends Target<File>
into(int width, int height)

Glide的downloadOnly()是将Image的二进制文件下载到硬盘缓存当中,以便在后续使用,可以在UI线程当中异步下载,也可以在异步线程当中同步调用下载,值得注意的是,如果在同步线程当中, 
downloadOnly使用一个target作为参数,而在异步线程当中则是使用width和height。 
在后台线程当中下载图片,可以通过如下的方式:

new Thread(new Runnable() {
        @Override
        public void run() {
            FutureTarget<File> future = Glide.with(applicationContext)
                                             .load(yourUrl)
                                             .downloadOnly(500, 500);
            File cacheFile = future.get();
        }
    }).start();

上面的调用只能在异步线程当中,如果在main Thread当中调用.get(),会阻塞主线程,会导致Crash。 
这个其实就是可以获取该Image的缓存路径,目前还没想好怎么封装一个获取缓存路径的通用类,有待研究。至于Glide的缓存策略,这里也简要介绍下,也是配置: 
缓存策略

.diskCacheStrategy(DiskCacheStrategy.ALL) //这个是设置缓存策略。
DiskCacheStrategy.NONE:不缓存 
DiskCacheStrategy.SOURCE:缓存原始图片 
DiskCacheStrategy.RESULT:缓存压缩过的结果图片 
DiskCacheStrategy.ALL:两个都缓存

10.转换器 
第七点中的centerCrop和fitCenter是Glide默认的两种转换器,现在已经有了Glide集成库,提供各式各样的Api可以将图片转为各种形状,例如圆形,圆角型等等,库呢在上面已经介绍过啦,下面就来使用这些库看看效果。 
(1)单独转换器效果(毛玻璃为例)
Glide.with(this).load(R.mipmap.login).bitmapTransform(new BlurTransformation(this, 20)).into(imageView);
可以看到毛玻璃效果,BlurTransformation就是库提供的类,20这个数字是毛玻璃的模糊程度设置,注意范围是1~25,否则图片将不会显示出来。 
(2)复合转换器效果
Glide.with(this).load(R.mipmap.login).bitmapTransform(new BlurTransformation(this, 20), new CropCircleTransformation(this)).into(imageView);
可以看到,图片不仅变成毛玻璃,还变成了圆形。 
我们可以来看看bitmapTransform这个方法:

public DrawableRequestBuilder<ModelType> bitmapTransform(Transformation<Bitmap>... bitmapTransformations) {
        GifBitmapWrapperTransformation[] transformations =
                new GifBitmapWrapperTransformation[bitmapTransformations.length];
        for (int i = 0; i < bitmapTransformations.length; i++) {
            transformations[i] = new GifBitmapWrapperTransformation(glide.getBitmapPool(), bitmapTransformations[i]);
        }
        return transform(transformations);
    }

可以通过看代码发现,bitmapTransform这个方法可以传入多种转换器,实现不同的效果,变通性很强。 
下面我来列一下多种Transformations,具体的我也不展示了,留给大家去尝试: 
Crop 
默认:CropTransformation, 
圆形:CropCircleTransformation, 
方形:CropSquareTransformation, 
圆角:RoundedCornersTransformation

Color 
颜色覆盖:ColorFilterTransformation, 
置灰:GrayscaleTransformation

Blur 
毛玻璃:BlurTransformation

Mask 
还未弄明白:MaskTransformation

尝试完这些,你就可以发现Glide的强大之处! 
当然,除了上面库提供的这些,还可以自定义转换器。 
第一步、编写转换器类 
继承BitmapTransformation:

private static class MyTransformation extends BitmapTransformation {
    public MyTransformation(Context context) {
       super(context);
    }
    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, 
            int outWidth, int outHeight) {
       Bitmap myTransformedBitmap = ... // 在这里自定义图片转换,跟平时自己裁剪截图什么的一样
       return myTransformedBitmap;
    }
    @Override
    public String getId() {
        // Return some id that uniquely identifies your transformation.
        return "com.example.myapp.MyTransformation";
    }
}

第二步、在Glide方法链当中用.transform(…)替换fitCenter()/centerCrop()

Glide.with(context)
    .load(Url)
    .transform(new MyTransformation(context))
    .into(imageView);

在上面使用过程当中没有设置尺寸值,那么转换器转换的图片尺寸怎么确定呢,Glide实际上已经足够智能根据view的尺寸来确定转换图片的尺寸了,如果需要自定义尺寸,而不是用view和target当中的尺寸,那么可以使用override(int,int)设置相关的宽和高。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值