图片加载框架之Glide和Picasso

Posted 码上加油站

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图片加载框架之Glide和Picasso相关的知识,希望对你有一定的参考价值。

Glide介绍

Glide是一个加载图片的库,作者是bumptech,它是在泰国举行的google 开发者论坛上google为我们介绍的,这个库被广泛的运用在google的开源项目中。

Glide是一个非常成熟的图片加载库,他可以从多个源加载图片,如:网路,本地,Uri等,更重要的是他内部封装了非常好的缓存机制并且在处理图片的时候能保持一个低的内存消耗。

Picasso介绍(毕加索)

picasso是Square公司开源的一个android图形缓存库,地址http://square.github.io/picasso/,可以实现图片下载和缓存功能。仅仅只需要一行代码就能完全实现图片的异步加载

1.在adapter中需要取消已经不在视野范围的ImageView图片资源的加载,否则会导致图片错位,Picasso已经解决了这个问题。

2.使用复杂的图片压缩转换来尽可能的减少内存消耗

3.自带内存和硬盘二级缓存功能

二者用法类似,根据gihthub上添加依赖库,添加联网权限


区别:

区别一:with的参数

将Activity/Fragment作为with参数的好处:图片加载和Activity/Fragment的生命周期保持一致,比如Pause状态暂停加载,在resume时候重新加载,建议传参的时候给Activity/Fragment给Glide而不是context

区别二:图片质量

Glide默认的bitmap格式为RGB_565

Picasso默认的bitmap格式为ARGB_8888

区别三:加载Gif图片

Glide的一个明显的优点就是它可以加载gif图片,用Picasso加载的gif图片是不会动的

因为Glide被设计成能和Activity/Fragment的生命周期完美的相结合,因此gif动画将随着Activity/Fragment的生命周期自动的开始和停止。

gif的缓存和一般的图片也是一样的,也是第一次加载的时候调整大小,然后缓存。

注意:gif图片将消耗非常多的内存,因此要慎用。

区别四:缓存策略和加载速度

Picasso的缓存是全尺寸的,而Glide的缓存根据ImageView的尺寸相同

将ImageView调整成不同的大小,不管大小如何,Picasso值缓存一个全尺寸的,Picasso则需要在显示前重新调整大小而导致一下延迟.

而Glide不同,它会为每种大小尺寸缓存一下,加载速度比Picasso更快,磁盘策略比Picasso更好,但需要更大的空间来缓存,Glide比Picasso更有利于减少OOM的发生


基本用法

Glide.with(this).load(url).into(imageView);
Picasso.with(this).load(url).into(imageView);

Glide:修改缓存大小、位置、加载图片质量的实现

自定义一个glideConfigModule.java实体类继承GlideModule

import android.content.Context;

import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPool;
import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory;
import com.bumptech.glide.load.engine.cache.LruResourceCache;
import com.bumptech.glide.module.GlideModule;


public class GlideConfigModule implements GlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        // 指定位置在packageName/cache/glide_cache,大小为MAX_CACHE_DISK_SIZE的磁盘缓存
        builder.setDiskCache(new InternalCacheDiskCacheFactory(context, "glide_cache", 10*1024*1024));
        //指定内存缓存大小 Runtime.getRuntime().maxMemory()运行的最大内存值
        builder.setMemoryCache(new LruResourceCache(10*1024*1024));
        //全部的内存缓存用来作为图片缓存
        builder.setBitmapPool(new LruBitmapPool(10*1024*1024));
        //设置图片质量格式,设置和Picasso配置一样
        builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);/
    }

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

    }
}

 在清单文件中配置

<meta-data
    android:name="com.jcf.glidedemo.GlideConfigModule"
    android:value="GlideModule"/>

Glide:不为ImageView类型加载的实现

譬如加载的控件类型不是ImageView,是个自定义的布局。或者加载为Background的形式。可以使用SimpleTarget类型,这里指定他的大小为500*100,加载为背景图片。

.into(new SimpleTarget<GlideDrawable>(500,200) {
    @Override
    public void onResourceReady(GlideDrawable glideDrawable, GlideAnimation<? super GlideDrawable> glideAnimation) {
         tv.setBackground(glideDrawable); 
    }
});

 Picasso自定义截取图片的实现

import android.graphics.Bitmap;
import com.squareup.picasso.Transformation;
public class CropSquareTransformation implements Transformation {
    @Override
    public Bitmap transform(Bitmap bitmap) {
        int size = Math.min(bitmap.getWidth(), bitmap.getHeight());
        int x = (bitmap.getWidth() - size) / 2;
        int y = (bitmap.getHeight() - size) / 2;
        Bitmap result = Bitmap.createBitmap(bitmap, x, y, size, size);
        if (result != bitmap) {
            bitmap.recycle();
        }
        return result;
    }
    @Override
    public String key() {
        return "square()";
    }
}

 使用

Picasso.with(this)
        .load(url)
        .transform(new CropSquareTransformation())
        .into(ivPicasso);

二者在开发中用法

Glide.with(this)
            .load("https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1483868451&di=2c4c2a41347e49eca30ee3a2276034c0&src=http://file27.mafengwo.net/M00/B2/12/wKgB6lO0ahWAMhL8AAV1yBFJDJw20.jpeg")
            .crossFade()
            .listener(mRequestListener)//配置监听器
            .animate(android.R.anim.slide_in_left) //配置自带淡出淡入动画
            //.animate(R.anim.scale) //可设置自定义的动画
            .override(100, 100) //为图片重新定义大小
            .placeholder(R.mipmap.ic_launcher)//加载中的图片
            //.fitCenter() //根据布局大小填充图片,必须和centerCrop一起设置设置fitCenter(),不能再调用override()
            //.centerCrop() //图片要填充整个控件,去两边留中间
            .error(R.mipmap.ic_launcher)//加载失败的涂料
            .priority(Priority.HIGH) //优先级
            .into(ivGlide);//加载到控件上
    Picasso.with(this)
           // .load("https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1483868451&di=2c4c2a41347e49eca30ee3a2276034c0&src=http://file27.mafengwo.net/M00/B2/12/wKgB6lO0ahWAMhL8AAV1yBFJDJw20.jpeg")
            .load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1483885293073&di=4d6626505c2c3ca8a9e7f580c08884a8&imgtype=0&src=http%3A%2F%2Fimg5.duitang.com%2Fuploads%2Fitem%2F201510%2F30%2F20151030165654_fyUJW.thumb.700_0.gif")
            .error(R.mipmap.ic_launcher)
            //.fit()   //控件不能设置成wrap_content,也就是必须有大小才行,fit()才让图片的宽高等于控件的宽高,设置fit(),不能再调用resize()
            //.centerCrop()  //图片要填充整个控件,去两边留中间
            .resize(100,100) ////为图片重新定义大小
            .placeholder(R.mipmap.ic_launcher)
            .priority(Picasso.Priority.HIGH)
            .into(ivPicasso);
}
private RequestListener<String, GlideDrawable> mRequestListener = new RequestListener<String, GlideDrawable>() {
    @Override
    public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
        //显示错误信息
        Log.w(TAG, "onException: ", e);
        //打印请求URL
        Log.d(TAG, "onException: " + model);
        //打印请求是否还在进行
        Log.d(TAG, "onException: " + target.getRequest().isRunning());
        return false;
    }

    @Override
    public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
        if (isFromMemoryCache) {
            //如果是从缓存加载,设置动画效果
            ivGlide.setAnimation(AnimationUtils.loadAnimation(MainActivity.this, R.anim.scale));
        }
        //返回true表示拦截不再传递,false表示事件会传递下去
        return false;

    }
};

 Picasso圆形图片的实现

 

// 自定义Transformation
Transformation transform = new Transformation() {
        @Override
        public Bitmap transform(Bitmap source) {
            int size = Math.min(source.getWidth(), source.getHeight());
            int x = (source.getWidth() - size) / 2;
            int y = (source.getHeight() - size) / 2;
            Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
            if (squaredBitmap != source) {
                source.recycle();
            }
            Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());
            Canvas canvas = new Canvas(bitmap);
            Paint paint = new Paint();
            BitmapShader shader = new BitmapShader(squaredBitmap,
                    BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
            paint.setShader(shader);
            paint.setAntiAlias(true);
            float r = size / 2f;
            canvas.drawCircle(r, r, r, paint);
            squaredBitmap.recycle();
            return bitmap;
        }

        @Override
        public String key() {
            return "circle";
        }
    };

Picasso
        .with(this)// 指定Context
        .load(URL_IMG2) //指定图片URL
        .transform(transform) // 指定图片转换器
        .into(imageView); // 指定显示图片的ImageView

Picasso圆形图片的实现
class RoundedTransformation implements com.squareup.picasso.Transformation {
    private final int radius;
    private final int margin;  // dp

    // radius is corner radii in dp
    // margin is the board in dp
    public RoundedTransformation(final int radius, final int margin) {
        this.radius = radius;
        this.margin = margin;
    }

    @Override
    public Bitmap transform(final Bitmap source) {
        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));

        Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        canvas.drawRoundRect(new RectF(margin, margin, source.getWidth() - margin, source.getHeight() - margin), radius, radius, paint);

        if (source != output) {
            source.recycle();
        }

        return output;
    }

    @Override
    public String key() {
        return "rounded(radius=" + radius + ", margin=" + margin + ")";
    }
}

Picasso
        .with(this)// 指定Context
        .load(URL_IMG2) //指定图片URL
        .transform(new RoundedTransformation(360,0)) // 指定图片转换器
        .into(imageView); // 指定显示图片的ImageView

 


Glide显示圆形图片的实现

 

class GlideCircleTransform extends BitmapTransformation {
    public GlideCircleTransform(Context context) {
        super(context);
    }

    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        return circleCrop(pool, toTransform);
    }

    private Bitmap circleCrop(BitmapPool pool, Bitmap source) {
        if (source == null) return null;

        int size = Math.min(source.getWidth(), source.getHeight());
        int x = (source.getWidth() - size) / 2;
        int y = (source.getHeight() - size) / 2;

        // TODO this could be acquired from the pool too
        Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);

        Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        float r = size / 2f;
        canvas.drawCircle(r, r, r, paint);
        return result;
    }

    @Override
    public String getId() {
        return getClass().getName();
    }
}

Glide
        .with(this) // 指定Context
        .load(URL_GIF)// 指定图片的URL
        .transform(new GlideCircleTransform(this)) // 指定自定义图片样式
        .into(imageView);//指定显示图片的ImageView

 Glide显示圆角图片的实现

class GlideRoundTransform extends BitmapTransformation {

    private  float radius = 0f;

    public GlideRoundTransform(Context context) {
        this(context, 4);
    }

    public GlideRoundTransform(Context context, int dp) {
        super(context);
        this.radius = Resources.getSystem().getDisplayMetrics().density * dp;
    }

    @Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        return roundCrop(pool, toTransform);
    }

    private Bitmap roundCrop(BitmapPool pool, Bitmap source) {
        if (source == null) return null;

        Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight());
        canvas.drawRoundRect(rectF, radius, radius, paint);
        return result;
    }

    @Override public String getId() {
        return getClass().getName() + Math.round(radius);
    }
}

Glide
        .with(this) // 指定Context
        .load(URL_GIF)// 指定图片的URL
        .transform(new GlideRoundTransform(this,30)) // 指定自定义图片样式
        .into(imageView);//指定显示图片的ImageView

 

 

 

 

 

 

 

 


 

以上是关于图片加载框架之Glide和Picasso的主要内容,如果未能解决你的问题,请参考以下文章

Android图片加载与缓存开源框架总结七部曲:Glide Picasso ImageLoader Fresco ASimpleCache等

Glide 图片框架

最新源码Glide4.12框架之加载图片流程源码分析

最新源码Glide4.12框架之加载图片流程源码分析

最新源码Glide4.12框架之加载图片流程源码分析

最新源码Glide4.12框架之加载图片流程源码分析