• 图片加载之Glide使用总结


    概述

    作为Glide是谷歌推荐的图片加载库,Glide又着 支持video,Gif,SVG格式,同时有着很好的生命周期管理,支持Volley,OkHttp,更好的内存管理策略等优点。

    相关方法

    • with():指定了声明周期
    • load():加载资源,String/Uri/File/Integer/URL/byte[]/T,或者 loadFromMediaStore(Uri uri)
    • placeholder(resourceId/drawable): 设置资源加载过程中的占位Drawable。
    • error():load失败时显示的Drawable。
    • crossFade()/crossFade(int duration):imageView改变时的动画,version 3.6.1后默认开启300毫秒
    • dontAnimate():移除所有的动画。
    • override() :调整图片大小
    • centerCrop():图片裁剪,ImageView 可能会完全填充,但图像可能不会完整显示。
    • fitCenter(): 图像裁剪,图像将会完全显示,但可能不会填满整个 ImageView。
    • animate(): 指定加载动画。
    • transform():图片转换。
    • bitmapTransform(): bitmap转换,不可以和(centerCrop() 或 fitCenter())共用。
    • priority(Priority priority):当前线程的优先级,Priority.IMMEDIATE,Priority.HIGH,Priority.NORMAL(default),Priority.LOW
    • thumbnail(): 缩略图.
    • listener():异常监听
    • preload(int width, int height): 预加载resource到缓存中(单位为pixel)
    • fallback(Drawable drawable):设置model为空时显示的Drawable。
    • using() :为单个的请求指定一个 model
    • asGif():Gif 检查,如果是图片且加了判断,则会显示error占位图,否则会显示图片
    • asBitmap():bitmap转化,如果是gif,则会显示第一帧

    Glide 可以以load(File)的形式播放本地视频,但是如果需要播放网络视屏,则要用VideoView

    缓存策略

    一张图片变化很快,需要禁止内存缓存

    .skipMemoryCache(true)

    即使关闭内存缓存,请求图片将会仍然被存储在设备的磁盘缓存中,如果一张图片变化很快,仍需要禁止磁盘缓存

    .diskCacheStrategy(DiskCacheStrategy.NONE)

    Glide 缓存了原始图像,全分辨率图像和另外小版本的图像,因此禁用磁盘缓存是用枚举来控制的

    DiskCacheStrategy.NONE //什么都不缓存,就像刚讨论的那样
    DiskCacheStrategy.SOURCE //仅仅只缓存原来的全分辨率的图像。在我们上面的例子中,将会只有一个 1000x1000 像素的图片
    DiskCacheStrategy.RESULT //仅仅缓存最终的图像,即,降低分辨率后的(或者是转换后的)
    DiskCacheStrategy.ALL //缓存所有版本的图像(默认行为)

    Glide使用InternalCacheDiskCacheFactory类建立磁盘缓存。目录在
    /data/data/<package-name>/cache,其他应用程序无法访问。

    自定义缓存策略:

    磁盘缓存,用类DiskLruCacheWrapper来设置目录

    builder.setDiskCache(new DiskCache.Factory() {
                @Override
                public DiskCache build() {
                // 自己的缓存目录
                    File imgFile = new File(Environment.getExternalStorageDirectory()+"/Android/data/package-name");
                    return DiskLruCacheWrapper.get(imgFile,DiskCache.Factory.DEFAULT_DISK_CACHE_SIZE);
                }
            });

    内存缓存,用类Memory Cache 来设置大小

    MemorySizeCalculator calculator = new MemorySizeCalculator(context); 
    builder.setMemoryCache(new LruResourceCache(calculator.getMemoryCacheSize()));

    Bitmap Pool

    重复使用及销毁策略。设置方法:GlideBuilder.setBitmapPool()
    默认采用的是LruBitmapPool,使用了LRU算法。

    MemorySizeCalculator calculator = new MemorySizeCalculator(context);
    int defaultBitmapPoolSize = calculator.getBitmapPoolSize();
    int customBitmapPoolSize = (int) (1.2 * defaultBitmapPoolSize);
    builder.setBitmapPool( new LruBitmapPool( customBitmapPoolSize );

    Bitmap Format

    Bitmap Format用于设置全局缺省首选Bitmap规格,设置方法:GlideBuilder.setDecodeFormat()
    默认采用RGB_565(比ARGB_8888节省一半的内存),但不支持透明度。

    优先级

    会发现优先级高的先 显示出来,即是图片比较大。

        //优先加载
        Glide
            .with(context)
            .load(heroImageUrl)
            .priority(Priority.HIGH)
            .into(imageViewHero);
        //后加载
        Glide
            .with(context)
            .load(itemImageUrl)
            .priority(Priority.LOW)
            .into(imageViewItem);

    先显示缩略图,后显示原图

       //用原图的1/10作为缩略图
        Glide
            .with(this)
            .load("http://inthecheesefactory.com/uploads/source/nestedfragment/fragments.png")
            .thumbnail(0.1f)
            .into(iv_0);
        //用其它图片作为缩略图
        DrawableRequestBuilder<Integer> thumbnailRequest = Glide
            .with(this)
            .load(R.drawable.news);
        Glide.with(this)
            .load("http://inthecheesefactory.com/uploads/source/nestedfragment/fragments.png")
            .thumbnail(thumbnailRequest)
            .into(iv_0);

    图片处理

    裁剪、模糊、滤镜等。可以s使用 wasabeef/glide-transformations

    实现Transformation 接口,或者使用抽象类BitmapTransformation,
    通过transform()或bitmapTransform()来处理图片

        //圆形裁剪
        Glide.with(this)
            .load("http://inthecheesefactory.com/uploads/source/nestedfragment/fragments.png")
            .bitmapTransform(new CropCircleTransformation(this))
            .into(iv_0);
        //圆角处理
        Glide.with(this)
            .load("http://inthecheesefactory.com/uploads/source/nestedfragment/fragments.png")
            .bitmapTransform(new RoundedCornersTransformation(this,30,0, RoundedCornersTransformation.CornerType.ALL))
            .into(iv_0);
        //灰度处理
        Glide.with(this)
            .load("http://inthecheesefactory.com/uploads/source/nestedfragment/fragments.png")
            .bitmapTransform(new GrayscaleTransformation(this))
            .into(iv_0);
        //模糊处理
        Glide.with(this).load(R.drawable.demo)
                .bitmapTransform(new BlurTransformation(context))
                .into((ImageView) findViewById(R.id.image));
        //其它变换...

    自定义转换

    public class BlurTransformation extends BitmapTransformation {
    
        public BlurTransformation(Context context) {
            super( context );
        }
    
        @Override
        protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
            return null; // todo
        }
    
        @Override
        public String getId() {
            return null; // todo
        }
    }

    其中getId() :描述了这个转换的唯一标识符,将作为缓存系统的一部分

    可以使用单种转换和多种转换,如多种转换:

    Glide  
        .with( context )
        .load( eatFoodyImages[1] )
        .transform( new GreyscaleTransformation( context ), new BlurTransformation( context ) )
        .into( imageView2 );

    回调 Target

    SimpleTarget

    target 泛型:Bitmap,GlideDrawable,GifDrawable
    其中使用字段声明target’而不是使用匿名内部类的形式,可以避免被垃圾回收机制回收,而回调为空的现象。

    private SimpleTarget target = new SimpleTarget<Bitmap>() {  
        @Override
        public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
            // do something with the bitmap
            // for demonstration purposes, let's just set it to an ImageView
            imageView1.setImageBitmap( bitmap );
        }
    };
    
    private void loadImageSimpleTarget() {  
        Glide
            .with( context ) // could be an issue!
            .load( eatFoodyImages[0] )
            .asBitmap()
            .into( target );
    }

    Target生命周期

    with( context ):关系到生命周期。如果请求需要在 activity 生命周期之外去做时,需要使用:

    private void loadImageSimpleTargetApplicationContext() {  
        Glide
            .with( context.getApplicationContext() ) // safer!
            .load( eatFoodyImages[1] 
            .asBitmap()
            .into( target2 );
    }

    Target 指定尺寸

    使用ImageView 作为参数给 .into()的时候,Glide 会用 ImageView 的大小去限制图像的大小
    但是target并没有已知的大小,如果知道图片大小则应指出,减少内存消耗。

    private SimpleTarget target2 = new SimpleTarget<Bitmap>( 250, 250 ) {  
        @Override
        public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
            imageView2.setImageBitmap( bitmap );
        }
    };
    
    private void loadImageSimpleTargetApplicationContext() {  
        Glide
            .with( context.getApplicationContext() ) // safer!
            .load( eatFoodyImages[1] )
            .asBitmap()
            .into( target2 );
    }

    ViewTarget

    常用于自定以控件中,比如自定义控件中组合了ImageView控件,如下

    public class FutureStudioView extends FrameLayout {  
        ImageView iv;
        TextView tv;
    
        public void initialize(Context context) {
            inflate( context, R.layout.custom_view_futurestudio, this );
    
            iv = (ImageView) findViewById( R.id.custom_view_image );
            tv = (TextView) findViewById( R.id.custom_view_text );
        }
    
        public FutureStudioView(Context context, AttributeSet attrs) {
            super( context, attrs );
            initialize( context );
        }
    
        public FutureStudioView(Context context, AttributeSet attrs, int defStyleAttr) {
            super( context, attrs, defStyleAttr );
            initialize( context );
        }
    
        public void setImage(Drawable drawable) {
            iv = (ImageView) findViewById( R.id.custom_view_image );
    
            iv.setImageDrawable( drawable );
        }
    }

    使用如下方法给自定义控件中的ImageView设置图片

    private void loadImageViewTarget() {  
        FutureStudioView customView = (FutureStudioView) findViewById( R.id.custom_view );
    
        //传递了参数 customView
        viewTarget = new ViewTarget<FutureStudioView, GlideDrawable>( customView ) {
            @Override
            public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
            //调用了FutureStudioView的setImage方法
                this.view.setImage( resource.getCurrent() );
            }
        };
    
        Glide
            .with( context.getApplicationContext() ) // safer!
            .load( eatFoodyImages[2] )
            .into( viewTarget );
    }

    NotificationTarget

    用于加载图片到通知栏和应用小部件中的,具体见 http://mrfu.me/

    动画

    animate() :可以加载资源文件animate.xml文件
    或者 属性动画:

    • ViewPropertyAnimation
    • ViewAnimation
    • NoAnimation
    • DrawableCrossFadeViewAnimation
    ViewPropertyAnimation.Animator animationObject = new ViewPropertyAnimation.Animator() {  
        @Override
        public void animate(View view) {
            // if it's a custom view class, cast it here
            // then find subviews and do the animations
            // here, we just use the entire view for the fade animation
            view.setAlpha( 0f );
    
            ObjectAnimator fadeAnim = ObjectAnimator.ofFloat( view, "alpha", 0f, 1f );
            fadeAnim.setDuration( 2500 );
            fadeAnim.start();
        }
    };
    
    Glide  
        .with( context )
        .load( eatFoodyImages[1] )
        .animate( animationObject )
        .into( imageView2 );

    Glide module

    Glide module 是一个抽象方法,全局改变 Glide 行为的一个方式。
    前面单策略的定义中都用到了GlideBuilder类
    如果你需要访问 GlideBuilder,你需要去实现一个 GlideModule 接口的公共类

    public class FileGlideModule  implements GlideModule{
        @Override
        public void applyOptions(final Context context, GlideBuilder builder) {
    //builder 内的所有方法你都可以设置。
    //        builder.setDiskCache(new InternalCacheDiskCacheFactory(context));
            builder.setDiskCache(new ExternalCacheDiskCacheFactory(context));
          /*  builder.setDiskCache(new DiskCache.Factory() {
                @Override
                public DiskCache build() {
                    File imgFile = new File(Environment.getExternalStorageDirectory()+"/Android/data/com.leying365");
                    return DiskLruCacheWrapper.get(imgFile,DiskCache.Factory.DEFAULT_DISK_CACHE_SIZE);
                }
            });*/
            MemorySizeCalculator calculator = new MemorySizeCalculator(context);
            builder.setMemoryCache(new LruResourceCache(calculator.getMemoryCacheSize()));
            builder.setBitmapPool(new LruBitmapPool(calculator.getBitmapPoolSize()));
            builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
        }
    
        @Override
        public void registerComponents(Context context, Glide glide) {
    
        }
    }

    最终通过<meta-data android:name=”com.mypackage.MyGlideModule” tools:node=”GlideModule” /> 来生效

    常用方法:

    • setMemoryCache(MemoryCache memoryCache)
    • setBitmapPool(BitmapPool bitmapPool)
    • setDiskCache(DiskCache.Factory diskCacheFactory)
    • setDiskCacheService(ExecutorService service)
    • setResizeService(ExecutorService service)
    • setDecodeFormat(DecodeFormat decodeFormat)

    网络库

    Glide 使用ModeLoader 接口来 集成网络库,Glide提供了两种网络库 的实现,分别为OkHttp 和 Volley。

    在build.gradle中添加如下依赖,glide会默认使用OKhttp来做所有的网络连接

    dependencies {  
        // your other dependencies
        // ...
    
        // Glide
        compile 'com.github.bumptech.glide:glide:3.6.1'
    
        // Glide's OkHttp Integration 
        compile 'com.github.bumptech.glide:okhttp-integration:1.3.1@aar'
        compile 'com.squareup.okhttp:okhttp:2.5.0'
    }
    

    上面会将必要的GlideModule 到你的 Android.Manifest中。

    缓存与失效机制

    Glide 通过 url、viewwidth、viewheight、屏幕的分辨率等以一种散列算法生成一个独有、安全的文件名作为key保存到disk上.因为其是通过一个散列算法来实现的,因此很难定位文件的缓存,幸好Glide提供了signature()方法允许将一个附加的数据加入到缓存key当中,可以用来保证缓存的及时性.

    系统默认实现了MediaStoreSignature,StringSignature.

    Glide.with(fragment)
        .load(mediaStoreUri)
        .signature(new MediaStoreSignature(mimeType, dateModified, orientation))
        .into(view);

    当然也可以自己来实现Signature

    public class MSignature implements Key {
    
        @Override
        public boolean equals(Object o) {
         //...
        }
        @Override
        public int hashCode() {
           //...
        }
        @Override
        public void updateDiskCacheKey(MessageDigest messageDigest) {
            messageDigest.update(ByteBuffer.allocate(Integer.SIZE)
    .putInt(signature).array());
        }
    }

    极端情况,不缓存可以用diskCacheStrategy(DiskCacheStrategy.NONE.)来实现

    图片下载

    Glide除了提供into方法来加载图片外,也提供了downloadOnly方法来实现图片下载.

    FutureTarget<File> future = Glide.with(applicationContext)
        .load(yourUrl)
        .downloadOnly(500, 500);
    File cacheFile = future.get();

    下载之后可以通过如下方式来加载图片

    Glide.with(yourFragment)
        .load(yourUrl)
        //DiskCacheStrategy.ALL或者DiskCacheStrategy.SOURCE可以保证程序会先去读缓存文件
        .diskCacheStrategy(DiskCacheStrategy.ALL)
        .into(yourView);

    如果想获取一张图片的Bitmap,可以使用如下方式

    //此方法需要try/catch处理,并且最好在子线程中,否则会阻塞主线程
    Bitmap myBitmap = Glide.with(applicationContext)
        .load(yourUrl)
        .asBitmap()
        .centerCrop()
        //设置大小
        .into(500, 500)
        .get()

    参考:http://mrfu.me/

    使用demo:GlidePlayActivity.java

  • 相关阅读:
    exe自启动的几种方式
    关于 CShellManager 的作用
    DLL 调用 对话框 以及 如何获取调用dll 应用程序(窗口程序)的窗口句柄
    VC++ 2010 创建高级Ribbon界面详解(4)
    HPU--1221 Fibonacci数列
    取一个数的前几位
    HDU--1875 畅通工程再续
    POJ--2485 Highways
    【模板】HDU--1233 畅通工程
    hdu--1856 More is better
  • 原文地址:https://www.cnblogs.com/BoBoMEe/p/6415198.html
Copyright © 2020-2023  润新知