Gilde使用小结-基础


Glide是Google官方推荐使用的图片加载库。大哥已经表扬人家了,小弟们能不学习学习吗?如果你现在还在使用Picasso,那么先参考这篇文章对比一下Picasso和Glide。

添加依赖:

dependencies {
  compile 'com.github.bumptech.glide:glide:3.7.0'  # 添加Glide依赖
  compile 'jp.wasabeef:glide-transformations:2.0.0' # 可选,添加Glide变换第三方实现依赖。如果你对显示的图片有什么模糊啊,圆角什么的变换,那就添加了吧,省很多事。
  compile 'jp.co.cyberagent.android.gpuimage:gpuimage-library:1.3.0' # 可选,没用过,感兴趣GitHub上看看吧.
}

应付95%使用场合:

不说废话,直接上代码:

Glide
        .with(context)
        .load(imageUrl)  # 也可以是来自resouceId、File、Uri代表的图片资源。
        .placeHolder(resourceId) # 占位符,就是图片从开始请求到最后完全加载,这段时间显示的默认图片。
        .error(erroResouceId) #请求图片发生异常的错误图片。
        .into(targetImageView)

That's it!如果我没有估计错,这几行代码足够对付项目中大多数的图片加载需求了。对于ListView、GridView、RecyclerView等也不用担心,加载图片也就是这些代码,其它的什么条目不可见的时候自动取消加载图片的请求等等Glide都已经替我们解决好了。

还用一点我想大声对你说的就是Glide还可以加载gif。什么都不用改,只要你给的图片资源是gif人家就能放。有时候服务器那边脑子进水给你一个gif图片的url,但实际上是张静态图片,逻辑上这个应该算是加载错误图片资源,应该让error()显神威,不过Glide无法自动探知你就是想加载gif而其它类型都是错误,所以你得用asGif()明确告诉Glide:这里我就是要gif,其它类型的图片都是错误

Glide  
    .with( context )
    .load( gifUrl )
    .asGif()
    .error( R.drawable.full_cake )
    .into( imageViewGif );

还有时候你只想显示静态图片,但你是在怕了服务器那边,搞不好又进水在需要静态图片的地方给了gif,没关系,使用asBitmap()如果来的是一张gif只会显示它的第一帧:

Glide  
    .with( context )
    .load( gifUrl )
    .asBitmap()
    .into( imageViewGifAsBitmap );

注意一点的就是你给with()方法的context实例,Glide的生命周期会绑定到这个context的实例上,Glide在context不同生命周期回调中有不同的处理,例如图片请求在onStop()中会暂停,在onStart()中又会重新请求;gif在onStop()会暂停播放等等。所以Application、Activity、Fragment、Service等都可以提供context,你就要根据自己的情况慎重选择适合的context实例了。

Glide还可以播放本地视频,只是本地Android可以解码的视频类型哦!

String filePath = "/storage/emulated/0/Pictures/example_video.mp4";

Glide  
    .with( context )
    .load( Uri.fromFile( new File( filePath ) ) )
    .into( imageViewGifAsBitmap );

有时候一个页面有很多图片,但有主次之分。你希望主要的图片先被加载出来,之后在加载次要的图片。你可以通过指定请求优先级来实现这样的需求,有一点需要铭记在心的是:指定优先级只不过让优先级高的先请求,但由于图片大小,图片处理时间等等也需要时间,所以不能保证最后请求优先级高的一定最先显示
  先来看一下,Glide都有哪些请求优先级别:

Priority.LOW
Priority.NORMAL
Priority.HIGH
Priority.IMMEDIATE

见名知义,不解释了。最后用priority()指定请求优先级:

   Glide
        .with( context )
        .load( imageUrl )
        .priority( Priority.HIGH )
        .into( imageViewHero );

默认情况下根据给定的ImageView大小来决定要加载的图片大小。当然,你也可以使用override(horizontalSize, verticalSize)指定要加载的图片大小:

Glide
    .with(context)
    .load(imageUrl)
    .override(600, 200) 
    .into(imageViewResize);

不过这样做可能会破坏原图片的比例。所以你指定大小的时候,所以你还可以用fitCenter()或centerCrop()来缩放图片,用以达到比较好的视觉效果。

Glide
    .with(context)
    .load(imageUrl)
    .override(600, 200)
    .centerCrop()  #缩放图片以满足ImageView的尺寸,超过ImageView的部分将会被裁剪掉,因此最终图片可能不完全显示。
    .into(imageViewResizeCenterCrop);
Glide
    .with(context)
    .load(UsageExampleListViewAdapter.eatFoodyImages[0])
    .override(600, 200)
    .fitCenter()  #保持原图片的比例进行缩放,直到可以在ImageView中尺寸区域内完全显示图片。图片能够完全显示,比例保持不变,但是可能图片无法完全覆盖ImageView的区域。
    .into(imageViewResizeFitCenter);

图片从无到完全显示,Glide默认是有过渡动画的,还可用crossFade(int duration)来自定义过渡动画的毫秒数。当然如果你就是喜欢吓用户,想要突然间把图片加载出来了,可以用dontAnimate()取消过渡动画:

Glide
    .with(context)
    .load(UsageExampleListViewAdapter.eatFoodyImages[0])
    .placeholder(R.mipmap.ic_launcher) 
    .error(R.mipmap.future_studio_launcher) 
    .dontAnimate()
    .into(imageViewFade);
Glide缓存使用

不用说,Glide当然会在内存和本地缓存已经请求过的图片。但有时一个url对应的图片内容变动比较大,不需要把它缓存在内存或者本地。那么可以使用skipMemoryCache(true):

Glide  
    .with( context )
    .load( imageUrl)
    .skipMemoryCache( true )
    .into( imageViewInternet );

当然这只是告诉Glide图片不要在内存中缓存,Glide在本地还会照样缓存请求过的图片的。可以用diskCacheStrategy()取消本地缓存。要明白一点的是Glide对于一张从网络请求来的图片,Glide除了会在本地存储原始尺寸的图片,还会缓存加载到ImageView的较小尺寸的图片。因此diskCacheStrategy()可以接受:

  • DiskCacheStrategy.NONE 本地什么都不缓存
  • DiskCacheStrategy.SOURCE 本地缓存原始的全尺寸图片
  • DiskCacheStrategy.RESULT 本地缓存加载到ImageView上的较小尺寸的图片
  • DiskCacheStrategy.ALL 默认缓存全部尺寸的图片
Glide  
    .with( context )
    .load( imageUrl)
    .diskCacheStrategy( DiskCacheStrategy.SOURCE )
    .into( imageViewFile );
自定义变换:

有时候在图片显示之前,会需要对图片进行一些变换,最常出现的需求就是将图片模糊。自定义变换主要就是实现Transformation接口,要知道我们的Glide还可以比方gif和视频,因此实现这个接口难度会大很多。当然如果只是针对静态图片,实现BitmapTransformation会容易很多:

public class BlurTransformation extends BitmapTransformation {

    private RenderScript rs;

    public BlurTransformation(Context context) {
        super( context );

        rs = RenderScript.create( context );
    }

    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        Bitmap blurredBitmap = toTransform.copy( Bitmap.Config.ARGB_8888, true );
        Allocation input = Allocation.createFromBitmap(
            rs, 
            blurredBitmap, 
            Allocation.MipmapControl.MIPMAP_FULL, 
            Allocation.USAGE_SHARED
        );
        Allocation output = Allocation.createTyped(rs, input.getType());
        ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
        script.setInput(input);
        script.setRadius(10);
        script.forEach(output);

        output.copyTo(blurredBitmap);

        toTransform.recycle();

        return blurredBitmap;
    }

    @Override
    public String getId() {
        return "blur";
    }
}

我们在transform方法里可以拿到要显示的图片toTransform以及ta的尺寸(outWidth, outHeight),接下来就可以发挥想象力处理图片然后把处理后的图片返回就像。关于上面图片模糊具体可以看这篇文章。然后就可以用transform()、或者bitmapTransform()方法来使用我们自定义的变换了:

Glide  
    .with( context )
    .load( imageUrl)
    .transform( new BlurTransformation( context ) )
    //.bitmapTransform( new BlurTransformation( context ) )  #这个方法接受的变换只针对bitmap。
    .into( imageView1 );

如果你要进行多种变换,transform()和bitmapTransform()可接受多个参数:

Glide  
    .with( context )
    .load( imageUrl )
    .transform( new GreyscaleTransformation( context ), new BlurTransformation( context ) )
    .into( imageView2 );

在最开始添加依赖时说过已经有好人实现了许多图片变换,看看这个glide-transformations项目。是不是感觉瞬间轻松许多。

自定义动画:

之前已经提到的crossFade()是个渐变动画,现在我们还想要自己定义的更帅的动画。可以使用animate()方法,ta可以接受一个动画的资源文件:

#R.anim.scale
<?xml version="1.0" encoding="utf-8"?>  
<set xmlns:android="http://schemas.android.com/apk/res/android"  
     android:fillAfter="true">

    <scale
        android:duration="@android:integer/config_longAnimTime"
        android:fromXScale="0.1"
        android:fromYScale="0.1"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1"
        android:toYScale="1"/>

</set>  
Glide  
    .with( context )
    .load( eatFoodyImages[0] )
    .animate( android.R.anim.slide_in_left ) 
    .into( imageView1 );ava

另外animate()还接受一个ViewPropertyAnimation.Animator实现:

ViewPropertyAnimation.Animator animationObject = new ViewPropertyAnimation.Animator() {  
    @Override
    public void animate(View view) {

        view.setAlpha( 0f );

        ObjectAnimator fadeAnim = ObjectAnimator.ofFloat( view, "alpha", 0f, 1f );
        fadeAnim.setDuration( 2500 );
        fadeAnim.start();
    }
};

只要实现一个animate方法就可以啦。animate方法中的view就是传入into方法里的ImageView对象:

Glide  
    .with( context )
    .load( imageUrl )
    .animate( animationObject )
    .into( imageView2 );

我这里好像发现当调用了crossFade()方法,animate()方法定义的动画好像不会被调用,也就是没有效果。另外好像过渡动画只对ImageView对象有效果,当传入into()方法的ViewTarget类型对象,crossFade()和animate()好像都不会调用。这个还有待继续验证。

回调:SimpleTarget和ViewTarget:

Target接口代表Glide中资源最终被加载到的地方并且可以毁掉Glide中的生命周期方法。Target可以回调的生命周期方法有:

  • onLoadStarted
  • onResourceReady
  • onLoadCleared
  • onLoadFailed
      典型的生命周期是:onLoadStarted -> onResourceReady 或者 onLoadFailed -> onLoadCleared。实际可能某些方法不会调用,例如加入直接从内存缓存中加载资源,onLoadStarted方法便不会被调用了。
      这里介绍两个Target实现类,同时也代表着两个常见的需求。
      有时候我们只是希望获得一张图片,而不想把它加载到什么地方上显示,对于这个需求使用SimpleTarget最合适不过了。
private SimpleTarget target = new SimpleTarget<Bitmap>() {  
    @Override
    public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {

       //在这里我们就可以获得加载的资源了,当然这里是一个bitmap。
    }
};

private void loadImageSimpleTarget() {  
    Glide
        .with( context )
        .load( imageUrl)
        .asBitmap()
        .into( target ); //使用Target。
}

这里有点要在强调一下,就是关于传给with()方法的context实例。要记得Glide的生命周期会和这个context实例的生命周期相绑定。所以可能会有这样的场景:在activityA中获得图片,你把这个activityA传给with()方法,然后还没获得图片,用户跳转到activityB,在activityB要显示这个图片。很显然activityA在回调onStop()的时候Glide也停止请求那张图片,所以在activityB中也就没有图片可显示啦。

还可以指定SimpleTarget获得的资源的尺寸:

private SimpleTarget target2 = new SimpleTarget<Bitmap>( 250, 250 ) {  
    @Override
    public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
        imageView2.setImageBitmap( bitmap );
    }
};

另一个需求那就更常见了,而且也更迫切。当你自定义一个view的时候,同时这个view还不是继承ImageView但是ta也有显示图片的需要,怎么办?用ViewTarget来办:

//自定义的一个ViewGroup
public class CustomView extends FrameLayout {  
    ImageView iv;
    TextView tv;

    public void initialize(Context context) {
        inflate( context, R.layout.custom_view_, this );

        iv = (ImageView) findViewById( R.id.custom_view_image );
        tv = (TextView) findViewById( R.id.custom_view_text );
    }

    public CustomView(Context context, AttributeSet attrs) {
        super( context, attrs );
        initialize( context );
    }

    public CustomView(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 );
    }
}

    CustomView customView = (CustomView) findViewById( R.id.custom_view );

    //定义一个ViewTarget,注意传入自定义View对象,还有ViewTarget的泛型。
    viewTarget = new ViewTarget<CustomView, GlideDrawable>( customView ) {
        @Override
        public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
          //这里我们获得传入的自定义View,在这个自定义View中我们写了该View设置图片的方法。
            this.view.setImage( resource.getCurrent() );
        }
    };

    Glide
        .with( context.getApplicationContext() ) 
        .load( eatFoodyImages[2] )
        .into( viewTarget ); //使用Target。
调试和错误处理:

可以使用ADB命令来查看资源请求时的日志:

adb shell setprop log.tag.GenericRequest DEBUG [还可选VERBOSE,INFO,WARN,ERROR日志级别] 

虽然有error()帮我们处理请求图片出错时的情况,但有时我们也想自己作一些处理,最起码得看看发生了什么是吧。用listener()注册一个RequestListener便可以得到请求资源时的一些关键回调方法:

private RequestListener<String, GlideDrawable> requestListener = new RequestListener<String, GlideDrawable>() {  
    @Override
    public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
        //获得异常你想怎么处理随你的便利。
        return false;  //如果返回true,Glide认为你已经处理好了这个异常,那么error()方法也就不会调用了。
    }

    @Override
    public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
        return false;
    }
};

Glide  
    .with( context )
    .load(UsageExampleListViewAdapter.eatFoodyImages[0])
    .listener( requestListener ) //注册监听器。
    .error( R.drawable.cupcake )
    .into( imageViewPlaceholder );

当然Glide还有其它的监听器也很有用,例如LifecycleListener就可以在Glide里监听Fragment和Activity的onStart()、onStop()和onDestroy()回调。

集成自己的网络库:

你可以使用自己的网络库,但这个细讲起来还比较复杂。这里介绍当你的工程使用的是OkHttp或者Volley的情况,稍微配置一下build.gradle,其它什么都不用做了:

dependencies {  
    // 其它配置

    
    compile 'com.github.bumptech.glide:glide:3.7.0'

    // 特别注意这个,就是ta让你可以使用OkHttp作为自己的网络请求库。
    compile 'com.github.bumptech.glide:okhttp-integration:1.4.0@aar'
    compile 'com.squareup.okhttp:okhttp:2.7.5'
    
    // 针对Volley的配置 。
   //compile 'com.github.bumptech.glide:volley-integration:1.4.0@aar'
  //compile 'com.mcxiaoke.volley:library:1.0.8'

    //针对OkHttp3的配置。
   //compile 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar'
  //compile 'com.squareup.okhttp3:okhttp:3.2.0'
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容