Android - 图片处理之Glide4.0版本

老婆保佑,代码无BUG

前言

一般项目我都会使用Glide作为我的图片加载框架,他和Picasso ,真的很像,郭大神早就分析过了,很详细,这里也就简单做个记录。小白白一枚,学习路上

Android图片加载框架最全解析(一),Glide的基本用法

Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流程

Android图片加载框架最全解析(三),深入探究Glide的缓存机制

Android图片加载框架最全解析(四),玩转Glide的回调与监听

Android图片加载框架最全解析(五),Glide强大的图片变换功能

Android图片加载框架最全解析(六),探究Glide的自定义模块功能

Android图片加载框架最全解析(七),实现带进度的Glide图片加载功能

Android图片加载框架最全解析(八),带你全面了解Glide 4的用法


目录

  • 一:GitHub
  • 二:下载使用
      1. Gradle
      1. Android SDK 要求
      • 解决方案
    • 3.权限
  • 二:apply && RequestOptions
  • 三:API 介绍
  • 四: 补充说明
      1. diskCacheStrategy参数补充
      1. asBitmap()注意坑
      1. submit()
      1. transforms
      • (1) 转成黑白
      • (2) 高斯模糊
      • (3) 圆形
      • (4 ) 圆角
  • 5.Generated API

一:GitHub

bumptech/glide

二:下载使用

点击,跳转到官网,介绍很详细

1. Gradle

repositories {
  mavenCentral()
  maven { url 'https://maven.google.com' }
}
dependencies {
    compile 'com.github.bumptech.glide:glide:4.4.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.4.0'
}

2. Android SDK 要求

  • Min Sdk Version - 使用 Glide 需要 min SDK 版本 API 14 (Ice Cream Sandwich) 或更高。
  • Compile Sdk Version - Glide 必须使用 API 26 (Oreo) 或更高版本的 SDK 来编译。
  • Support Library Version - Glide 使用的支持库版本为 27。

否则会出现如下异常


解决方案

dependencies {
    implementation 'com.android.support:appcompat-v7:27.0.2' //这个版本的就可以了
    implementation 'com.github.bumptech.glide:glide:4.4.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.4.0'
}

3.权限

 <uses-permission android:name="android.permission.INTERNET"/>
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

二:apply && RequestOptions

4.0之前最常用的方式,当然现在也是哈

Glide.with(this)
     .load(url)
     .into(img);

4.0之后,有一个新的东西

   Glide.with(this)
                .load(url)
//                .apply(RequestOptions options)
                .into(img);

比如 我们加载占位图和错误图

RequestOptions options = new RequestOptions()
        .error(R.drawable.error)
        .placeholder(R.drawable.loading);
Glide.with(this)
     .load(url)
     .apply(options)
     .into(imageView);

小伙伴们没看错,这样的方式,摆脱了,以前链式写法中,Glide很长很长,现在的话,我们可以传入一个RequestOptions,对象,就有小伙伴问了,有啥用,我觉得,比较容易封装,

例如

public class GlideUtil {

    public static void load(Context context,
                            String url,
                            ImageView imageView,
                            RequestOptions options) {
        Glide.with(context)
             .load(url)
             .apply(options)
             .into(imageView);
    }
}

三:API 介绍

API 介绍
占位符(Placeholder) 当请求正在执行时被展示的 Drawable
错误符(Error) 请求永久性失败时展示
后备回调符(Fallback) 在请求的url/model为 null 时展示
override 指定了一个图片的尺寸,Target.SIZE_ORIGINAL加载图片的原始尺寸
skipMemoryCache(true) 禁用内存缓存功能
diskCacheStrategy(DiskCacheStrategy.NONE) 禁用硬盘缓存功能,参数列表如下 四(1)
asBitmap() 只允许加载静态图片,。如果传入的是GIF图,会展示GIF图的第一帧
asFile() 指定文件格式 注意事项 如下 四(2)
asDrawable() 指定Drawable格式
submit() 使用如下四(3)
transforms 图片变换,Glide 默认有3个,如下四(4)

四: 补充说明

1. diskCacheStrategy参数补充

参数 说明
DiskCacheStrategy.NONE 表示不缓存任何内容。
DiskCacheStrategy.DATA 表示只缓存原始图片。
DiskCacheStrategy.RESOURCE 表示只缓存转换过后的图片。
DiskCacheStrategy.ALL 表示既缓存原始图片,也缓存转换过后的图片。
DiskCacheStrategy.AUTOMATIC 表示让Glide根据图片资源智能地选择使用哪一种缓存策略(默认选项)。

2. asBitmap()注意坑

熟悉Glide 3的朋友对asBitmap()方法肯定不会陌生对吧?但是千万不要觉得这里就没有陷阱了,在Glide 3中的语法是先load()再asBitmap()的,而在Glide 4中是先asBitmap()再load()的。乍一看可能分辨不出来有什么区别,但如果你写错了顺序就肯定会报错了

3. submit()

通过如下代码,可以获取到,下载好的图片放在哪,可以看到 都在cache

   new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    File file = Glide.with(MainActivity.this)
                            .asFile()
                            .load(url)
                            .submit()
                            .get();
                    Log.e("Tag", "path-->" + file.getPath());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }).start();


 E/Tag: path-->/data/user/0/com.allens.glidedemo/cache/image_manager_disk_cache/309df01e6362ddc8939a4e3c549e8276dffb0446a89f2facee371909301fe76a.0

4. transforms

内置有这3个

RequestOptions options = new RequestOptions()
        .centerCrop();

RequestOptions options = new RequestOptions()
        .fitCenter();

RequestOptions options = new RequestOptions()
        .circleCrop();//圆形

一般我们还会自己去定义,以下是常用的3种转换

使用起来也很简单

   RequestOptions options = new RequestOptions()
                .skipMemoryCache(true)
                .diskCacheStrategy(DiskCacheStrategy.NONE);
                //圆形
               .transforms(new CircleTransform(mContext,2, Color.DKGRAY))//外圈宽度,外圈颜色
                //黑白
               .transforms(new BlackWhiteTransformation());
               //高斯模糊 范围在 0 -- 25 越大模糊程度越高
               .transforms(new BlurTransformation(mContext, 25)); // (0 < r <= 25)
                //可以使用多种
               .transforms(new BlurTransformation(mContext, 25),new CircleTransform(mContext,2, Color.DKGRAY))

(1) 转成黑白

package com.allens.lib_glide.Transformation;

import android.graphics.Bitmap;
import android.media.ThumbnailUtils;
import android.support.annotation.NonNull;
import android.view.animation.Transformation;

import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;

import java.security.MessageDigest;

/**
 * 描述:
 * <p> 黑白
 * Created by allens on 2018/1/8.
 */

public class BlackWhiteTransformation extends BitmapTransformation {
    @Override
    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
        return convertToBlackWhite(toTransform);
    }

    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {

    }

    private Bitmap convertToBlackWhite(Bitmap bmp) {
        int width = bmp.getWidth(); // 获取位图的宽
        int height = bmp.getHeight(); // 获取位图的高
        int[] pixels = new int[width * height]; // 通过位图的大小创建像素点数组

        bmp.getPixels(pixels, 0, width, 0, 0, width, height);
        int alpha = 0xFF << 24;
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int grey = pixels[width * i + j];

                //分离三原色
                int red = ((grey & 0x00FF0000) >> 16);
                int green = ((grey & 0x0000FF00) >> 8);
                int blue = (grey & 0x000000FF);

                //转化成灰度像素
                grey = (int) (red * 0.3 + green * 0.59 + blue * 0.11);
                grey = alpha | (grey << 16) | (grey << 8) | grey;
                pixels[width * i + j] = grey;
            }
        }
        //新建图片
        Bitmap newBmp = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        //设置图片数据
        newBmp.setPixels(pixels, 0, width, 0, 0, width, height);

        Bitmap resizeBmp = ThumbnailUtils.extractThumbnail(newBmp, 380, 460);
        return resizeBmp;
    }
}

(2)高斯模糊

package com.allens.lib_glide.Transformation;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Build;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RSRuntimeException;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import android.support.annotation.NonNull;

import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;

import java.security.MessageDigest;

/**
 * 描述: 高斯模糊
 * <p>
 * Created by allens on 2018/1/8.
 */

public class BlurTransformation extends BitmapTransformation {


    private Context context;

    private float blurRadius;

    public BlurTransformation(Context context, float blurRadius) {
        this.context = context;
        this.blurRadius = blurRadius;
    }

    @Override
    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
        return blurBitmap(context, toTransform, blurRadius, outWidth, outHeight);
    }

    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {

    }

    /**
     * @param context   上下文对象
     * @param image     需要模糊的图片
     * @param outWidth  输入出的宽度
     * @param outHeight 输出的高度
     * @return 模糊处理后的Bitmap
     */
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    public Bitmap blurBitmap(Context context, Bitmap image, float blurRadius, int outWidth, int outHeight) {
        // 将缩小后的图片做为预渲染的图片
        Bitmap inputBitmap = Bitmap.createScaledBitmap(image, outWidth, outHeight, false);
        // 创建一张渲染后的输出图片
        Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);
        // 创建RenderScript内核对象
        RenderScript rs = RenderScript.create(context);
        // 创建一个模糊效果的RenderScript的工具对象
        ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
        // 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间
        // 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去
        Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
        Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
        // 设置渲染的模糊程度, 25f是最大模糊度
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            blurScript.setRadius(blurRadius);
        }
        // 设置blurScript对象的输入内存
        blurScript.setInput(tmpIn);
        // 将输出数据保存到输出内存中
        blurScript.forEach(tmpOut);
        // 将数据填充到Allocation中
        tmpOut.copyTo(outputBitmap);
        return outputBitmap;
    }

}

(3) 圆形

package com.allens.lib_glide.Transformation;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.NonNull;

import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;

import java.security.MessageDigest;

/**
 * 描述:
 * <p> 圆形
 * Created by allens on 2018/1/8.
 */

public class CircleTransform extends BitmapTransformation {
    private Paint mBorderPaint;
    private float mBorderWidth;

    public CircleTransform(Context context) {
        super(context);
    }

    public CircleTransform(Context context, int borderWidth, int borderColor) {
        super(context);
        mBorderWidth = Resources.getSystem().getDisplayMetrics().density * borderWidth;
        mBorderPaint = new Paint();
        mBorderPaint.setDither(true);
        mBorderPaint.setAntiAlias(true);
        mBorderPaint.setColor(borderColor);
        mBorderPaint.setStyle(Paint.Style.STROKE);
        mBorderPaint.setStrokeWidth(mBorderWidth);
    }

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

    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {

    }

    private Bitmap circleCrop(BitmapPool pool, Bitmap source) {
        if (source == null) {
            return null;
        }
        int size = (int) (Math.min(source.getWidth(), source.getHeight()) - (mBorderWidth / 2));
        int x = (source.getWidth() - size) / 2;
        int y = (source.getHeight() - size) / 2;
        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);
        if (mBorderPaint != null) {
            float borderRadius = r - mBorderWidth / 2;
            canvas.drawCircle(r, r, borderRadius, mBorderPaint);
        }
        return result;
    }
}

4.0 圆角

package com.starot.spark.transformation;


import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.NonNull;

import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;

import java.security.MessageDigest;

/**
 * 描述:
 * <p> 圆形
 *
 * @author allens
 * @date 2018/1/8
 */

public class CircleTransform extends BitmapTransformation {
    private Paint mBorderPaint;
    private float mBorderWidth;

    public CircleTransform(Context context) {
        super(context);
    }

    public CircleTransform(Context context, int borderWidth, int borderColor) {
        super(context);
        mBorderWidth = Resources.getSystem().getDisplayMetrics().density * borderWidth;
        mBorderPaint = new Paint();
        mBorderPaint.setDither(true);
        mBorderPaint.setAntiAlias(true);
        mBorderPaint.setColor(borderColor);
        mBorderPaint.setStyle(Paint.Style.STROKE);
        mBorderPaint.setStrokeWidth(mBorderWidth);
    }

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

    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {

    }

    private Bitmap circleCrop(BitmapPool pool, Bitmap source) {
        if (source == null) {
            return null;
        }
        int size = (int) (Math.min(source.getWidth(), source.getHeight()) - (mBorderWidth / 2));
        int x = (source.getWidth() - size) / 2;
        int y = (source.getHeight() - size) / 2;
        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);
        if (mBorderPaint != null) {
            float borderRadius = r - mBorderWidth / 2;
            canvas.drawCircle(r, r, borderRadius, mBorderPaint);
        }
        return result;
    }
}

5.Generated API

如果4.0用的不爽,就想使用3.0版本的那种链式写法,将Glide 关键字改成
GlideApp即可

GlideApp.with(this)
        .load(url)
        .placeholder(R.drawable.loading)
        .error(R.drawable.error)
        .skipMemoryCache(true)
        .diskCacheStrategy(DiskCacheStrategy.NONE)
        .override(Target.SIZE_ORIGINAL)
        .circleCrop()
        .into(imageView);

推荐阅读更多精彩内容