图片Android Architecture Components程序员

Glide4.0梳理

2017-08-28  本文已影响875人  我叫陆大旭
glide

Hi~ 我是Glide


现有图片框架介绍

1. Universal-Image-Loader(UIL)

2. Picasso

3. Fresco

4. Glide

总结

1.UIL和Picasso不支持Gif,这个是个硬伤。
2.Fresco体积过于庞大,除非是图片处理主导的应用,否则无法凸显它的价值。
3.Glide可以完成Picasso的功能,而且体积也比较小。所以一般项目首选。

其他

Picasso,Glide,Fresco对比分析
Fresco 与 Picasso 、Glide 的比较


Glide例子基于4.0

配置

project.gradle

dependencies {
    classpath 'com.android.tools.build:gradle:2.3.2'
    classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}

app.gradle

apply plugin: 'android-apt'

....

dependencies {
    //glide 4.0
    compile 'com.android.support:support-v4:23.1.1'
    compile 'com.github.bumptech.glide:glide:4.0.0'
    apt 'com.github.bumptech.glide:compiler:4.0.0'
}

基本用法

1、无需初始化
2、使用流接口
3、完整的请求需要3个参数

Glide.with(this)//获取上下文环境
                .load(url)//图片地址
                .into(imageView1);//图片显示的地方

加载其他来源的图片

1、资源文件

Glide.with(this).load(R.drawable.hsk1).into(imageView1);

2、本地图片

File file = new File("图片地址");
Glide.with(this).load(file).into(imageView1);

3、通过Uri方式

Uri uri = Uri.parse(url);
Glide.with(this).load(uri).into(imageView1);

占位符

GlideApp
.with(this)
.load(url)
.placeholder(R.drawable.image320)//加载的时候占位
.error(new ColorDrawable(Color.BLUE))//请求资源失败的时候
.fallback(new ColorDrawable(Color.CYAN))//当请求内容为null的时候显示
.into(imageView2);

GlideApp

在4.0中不用像3.X需要在AndroidManifest.xml配置GlideModule,而是通过注解继承AppGlideModule的子类来配置。

@GlideModule
public final class MyAppGlideModule extends AppGlideModule {}

使用的时候用GlideApp.with() 代替 Glide.with()

GlideApp
.with(fragment)
.load(myUrl)
.into(imageView)

如果GlideApp没有生成
1.检查一下配置文件
2.clean工程,build工程

选择项(RequestOptions)

基本的使用

RequestOptions requestOptions = new RequestOptions();
requestOptions.placeholder(R.drawable.image320);
GlideApp.with(this).load(url)
        .apply(requestOptions)
        .into(imageView3);

主要功能

占位符
requestOptions.placeholder(R.drawable.image320);
requestOptions.error(new ColorDrawable(Color.BLUE));
requestOptions.fallback(new ColorDrawable(Color.CYAN));
转换

转换成圆角图片

requestOptions.transform(new RoundedCorners(20));
缓存策略

跳过内存缓存,这个默认就是false。如果不需要就设置为true来确保不会缓存到内存中

requestOptions.skipMemoryCache(false);
磁盘缓存策略
requestOptions.diskCacheStrategy(DiskCacheStrategy.ALL);
图片设置
requestOptions.encodeFormat(Bitmap.CompressFormat.WEBP);//图片格式
requestOptions.encodeQuality(90);//图片质量
requestOptions.format(DecodeFormat.PREFER_RGB_565);//图片模式
requestOptions.override(40,40);//图片限制大小
其他
requestOptions.dontTransform();//禁止转换
requestOptions.dontAnimate();//禁止动画化

转换(Transform)

图片预处理

requestOptions.centerInside();
requestOptions.centerCrop();
requestOptions.circleCrop();
requestOptions.fitCenter();

如果当没有调用transform方法并且允许转变的情况下会进行以下处理:

public Target<TranscodeType> into(ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      if (requestOptions.isLocked()) {
        requestOptions = requestOptions.clone();
      }
      switch (view.getScaleType()) {
        case CENTER_CROP:
          requestOptions.optionalCenterCrop();
          break;
        case CENTER_INSIDE:
          requestOptions.optionalCenterInside();
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
          requestOptions.optionalFitCenter();
          break;
        case FIT_XY:
          requestOptions.optionalCenterInside();
          break;
        case CENTER:
        case MATRIX:
        default:
          // Do nothing.
      }
    }

自定义模糊转换

MyBlurTransformation.class

public class MyBlurTransformation extends BitmapTransformation {

    private static final String ID = "gift.witch.glide.MyBlurTransformation";
    private static final byte[] ID_BYTES = ID.getBytes(CHARSET);

    private static int MAX_RADIUS = 25;
    private static int DEFAULT_DOWN_SAMPLING = 1;

    private int mRadius;
    private int mSampling;
    private Context mContext;

    public MyBlurTransformation(Context context) {
        init(context, MAX_RADIUS, DEFAULT_DOWN_SAMPLING);
    }

    public MyBlurTransformation(Context context, BitmapPool pool) {
        init(context, MAX_RADIUS, DEFAULT_DOWN_SAMPLING);
    }

    public MyBlurTransformation(Context context, BitmapPool pool, int radius) {
        init(context, radius, DEFAULT_DOWN_SAMPLING);
    }

    public MyBlurTransformation(Context context, int radius) {
        init(context, radius, DEFAULT_DOWN_SAMPLING);
    }

    public MyBlurTransformation(Context context, int radius, int sampling) {
        init(context, radius, sampling);
    }

    private void init(Context context, int radius, int sampling) {
        mContext = context.getApplicationContext();
        mRadius = radius;
        mSampling = sampling;
    }

    @Override
    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {

        Bitmap source = getAlphaSafeBitmap(pool, toTransform);

        int width = source.getWidth();
        int height = source.getHeight();
        int scaledWidth = width / mSampling;
        int scaledHeight = height / mSampling;

        Bitmap bitmap = pool.get(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
        if (bitmap == null) {
            bitmap = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(bitmap);
        canvas.scale(1 / (float) mSampling, 1 / (float) mSampling);
        Paint paint = new Paint();
        paint.setFlags(Paint.FILTER_BITMAP_FLAG);
        canvas.drawBitmap(source, 0, 0, paint);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            try {
                bitmap = RSBlur.blur(mContext, bitmap, mRadius);
            } catch (RSRuntimeException e) {
                bitmap = FastBlur.blur(bitmap, mRadius, true);
            }
        } else {
            bitmap = FastBlur.blur(bitmap, mRadius, true);
        }

        if (!source.equals(toTransform)) {
            pool.put(source);
        }

        return bitmap;
    }

    private Bitmap getAlphaSafeBitmap(@NonNull BitmapPool pool,
                                             @NonNull Bitmap maybeAlphaSafe) {
        if (Bitmap.Config.ARGB_8888.equals(maybeAlphaSafe.getConfig())) {
            return maybeAlphaSafe;
        }

        Bitmap argbBitmap = pool.get(maybeAlphaSafe.getWidth(), maybeAlphaSafe.getHeight(),
                Bitmap.Config.ARGB_8888);
        new Canvas(argbBitmap).drawBitmap(maybeAlphaSafe, 0 /*left*/, 0 /*top*/, null /*pain*/);

        // We now own this Bitmap. It's our responsibility to replace it in the pool outside this method
        // when we're finished with it.
        return argbBitmap;
    }

    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {
        messageDigest.update(ID_BYTES);
        byte[] radiusData = ByteBuffer.allocate(4).putInt(mRadius).array();
        messageDigest.update(radiusData);
    }
}

使用

 RequestOptions requestOptions1 = new RequestOptions();
        requestOptions1.transform(new MyBlurTransformation(this));
        GlideApp.with(this)
                .load(url)
                .apply(requestOptions1)
                .into(imageView7);

目标(Target)

这里加载到的目标是simpleTarget,等加载完会返回resource像素图。

/**
 * 不显示到ImageView里
 */
SimpleTarget<Bitmap> simpleTarget = new SimpleTarget<Bitmap>(50,50){

    @Override
    public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
        imageView4.setImageBitmap(resource);
    }
};

GlideApp.with(this).asBitmap().load(url)
        .into(simpleTarget);

过渡(Transition)

有三种类型

GlideApp.with(this).asBitmap().load(url)
                .transition(BitmapTransitionOptions.withCrossFade())
                .into(imageView6);
通过TransitionOptions用动画资源文件自定义动画
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="10000">
    <alpha
        android:fromAlpha="0.5"
        android:toAlpha="1.0" />
    <scale
        android:fromXScale="0.5"
        android:fromYScale="0.5"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1.0"
        android:toYScale="1.0" />
</set>
BitmapTransitionOptions bitmapTransitionOptions =  new BitmapTransitionOptions();
bitmapTransitionOptions.transition(R.anim.glide_animate);

GlideApp.with(this).asBitmap().load(url)
                .transition(bitmapTransitionOptions)
                .into(imageView6);
通过TransitionOptions用ViewPropertyTransition.Animator自定义动画

public class MyAnimator implements ViewPropertyTransition.Animator {

    @Override
    public void animate(View view) {
        final View finalView = view;
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.setDuration(10000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = (float) animation.getAnimatedValue();
                finalView.setScaleX((float) (0.5 + 0.5 * value));
                finalView.setScaleY((float) (0.5 + 0.5 * value));
                finalView.setRotation(180* value);
                finalView.setAlpha(value);
            }
        });
        valueAnimator.start();
    }
}
BitmapTransitionOptions bitmapTransitionOptions =  new BitmapTransitionOptions();
bitmapTransitionOptions.transition(new MyAnimator());

GlideApp.with(this).asBitmap().load(url)
                .transition(bitmapTransitionOptions)
                .into(imageView6);

自定义GlideModule

@GlideModule
public final class MyAppGlideModule extends AppGlideModule {
    //注册自定义组件
    @Override
    public void registerComponents(Context context, Glide glide, Registry registry) {
    }

    //全局配置Glide
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
    }

    // 避免二次加载
    @Override
    public boolean isManifestParsingEnabled() {
        return false;
    }
}

全局配置

@Override
public void applyOptions(Context context, GlideBuilder builder) {
    // Default empty impl.
    //设置Bitmap的缓存池
    builder.setBitmapPool(new LruBitmapPool(30));

    //设置内存缓存
    builder.setMemoryCache(new LruResourceCache(30));

    //设置磁盘缓存
    builder.setDiskCache(new InternalCacheDiskCacheFactory(context));

    //设置读取不在缓存中资源的线程
    builder.setResizeExecutor(GlideExecutor.newSourceExecutor());

    //设置读取磁盘缓存中资源的线程
    builder.setDiskCacheExecutor(GlideExecutor.newDiskCacheExecutor());

    //设置日志级别
    builder.setLogLevel(Log.VERBOSE);

    //设置全局选项
    RequestOptions requestOptions = new RequestOptions();
    requestOptions.format(DecodeFormat.PREFER_RGB_565);
    builder.setDefaultRequestOptions(requestOptions);

}

自定义组件

Photo.class

public class Photo {

    private String url;


    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

}

PhotoModelLoader.class

public class PhotoModelLoader extends BaseGlideUrlLoader<Photo> {

    public static class Factory implements ModelLoaderFactory<Photo, InputStream> {

        private final ModelCache<Photo, GlideUrl> modelCache = new ModelCache<Photo, GlideUrl>(500);

        @Override
        public ModelLoader<Photo, InputStream> build(MultiModelLoaderFactory multiFactory) {
            return new PhotoModelLoader(multiFactory.build(GlideUrl.class, InputStream.class),
                    modelCache);
        }

        @Override
        public void teardown() {
        }
    }

    protected PhotoModelLoader(ModelLoader<GlideUrl, InputStream> concreteLoader) {
        super(concreteLoader);
    }

    protected PhotoModelLoader(ModelLoader<GlideUrl, InputStream> concreteLoader, @Nullable ModelCache<Photo, GlideUrl> modelCache) {
        super(concreteLoader, modelCache);
    }

    @Override
    protected String getUrl(Photo photo, int width, int height, Options options) {
        return photo.getUrl();
    }

    @Override
    public boolean handles(Photo photo) {
        return true;
    }

}

使用时,注册组件和模块加载器

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

    registry.append(Photo.class, InputStream.class,new PhotoModelLoader.Factory());
}

其他

设置优先级
 GlideApp.with(this).load(url).priority(Priority.HIGH)
设置缩略图
GlideApp.with(this).load(url).thumbnail(0.3f);
清除内存缓存(需要在UI线程里调用)
GlideApp.get(this).clearMemory();
清除磁盘缓存(需要在子线程里调用)
GlideApp.get(this).clearDiskCache();
Recycle的加载优化

只在拖动和静止时加载,自动滑动时不加载

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        switch (newState) {
            case RecyclerView.SCROLL_STATE_DRAGGING:
                Glide.with(MainActivity.this).resumeRequests();//加载
                break;
            case RecyclerView.SCROLL_STATE_SETTLING:
                Glide.with(MainActivity.this).pauseRequests();//暂停加载
                break;
            case RecyclerView.SCROLL_STATE_IDLE:
                Glide.with(MainActivity.this).resumeRequests();//加载
                break;
        }
    }
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
    }
});

参考

http://www.jianshu.com/p/5d156bdee68b
https://futurestud.io/tutorials/glide-getting-started

上一篇下一篇

猜你喜欢

热点阅读