OCNYang の 博客

Android 开发者,亦涉猎 Flutter

0%

Glide图片加载库的使用

Glide是 Google推荐的图片加载库,它可以支持来自url,Android资源,文件,Uri中的图片加载,同时还支持gif图片的加载,以及各种图片显示前的bitmap处理(例如:圆角图片,圆形图片,高斯模糊,旋转,灰度等等),缓存处理,请求优先级处理,动画处理,缩略图处理,图片大小自定义等等.可谓是非常的强大.

1.添加Glide库

需要在build.gradle中加入依赖,目前最新的版本是3.7.0,Glide库地址

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

2.加载网络图片

/**
 * Created by mChenys on 2016/6/6.
 */
public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        String url = "http://www.qq745.com/uploads/allimg/141106/1-141106153Q5.png";
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);
        Glide.with(this).
                load(url).
                asBitmap(). //强制处理为bitmap
                into(targetView);//显示到目标View中
    }
}

3.加载资源图片

public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        int resourceId = R.drawable.test;
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);
        Glide.with(this).
                load(resourceId).
                asBitmap().
                into(targetView);
    }
}

4.加载本地文件图片

public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        File file = new File(Environment.getExternalStorageDirectory(), "test.jpg");
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);
        Glide.with(this).
                load(file).
                asBitmap().
                into(targetView);
    }
}

5.从Uri中加载

/**
 * Created by mChenys on 2016/6/6.
 */
public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        Uri uri = Uri.parse("android.resource://" + this.getPackageName() + "/" + R.drawable.test);
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);
        Glide.with(this).
                load(uri).
                asBitmap().
                into(targetView);
    }
}

6.加载gif图片

public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);
        Glide.with(this).
                load(R.drawable.smail).
                asGif().//注意:这里显示的指明了要加载的是gif图片,当然即使不指明,glide也会自己判断.
                into(targetView);
    }
}

效果图:

7.设置默认图片和加载失败时显示的图片

public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);
        Glide.with(this).
                load(R.drawable.test).
                asBitmap().
                placeholder(R.drawable.bg_loading).//加载中显示的图片
                error(R.drawable.bg_error).//加载失败时显示的图片
                into(targetView);
    }
}

8.淡入显示效果

public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);
        Glide.with(this).
                load(R.drawable.test).
                placeholder(R.drawable.bg_loading).//加载中显示的图片
                error(R.drawable.bg_error).//加载失败时显示的图片
                crossFade().//淡入显示,注意:如果设置了这个,则必须要去掉asBitmap
                into(targetView);
    }
}

另外,crossFade还可以接收一个参数来设置淡入显示效果的持续时间,crossFade(int duration);
如果你想直接显示图片,而不是淡入显示图片,则可以通过dontAnimate()方法设置.

9.调整图片像素大小

public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);
        Glide.with(this).
                load(R.drawable.test).
                placeholder(R.drawable.bg_loading).//加载中显示的图片
                error(R.drawable.bg_error).//加载失败时显示的图片
                crossFade(1000).//淡入显示的时间,注意:如果设置了这个,则必须要去掉asBitmap
                override(80,80).//设置最终显示的图片像素为80*80,注意:这个是像素,而不是控件的宽高
                into(targetView);
    }
}

10.设置CenterCrop,FitCenter

CenterCrop,FitCenter都是对目标图片进行裁剪,了解过ImageView的ScaleType属性就知道,这2种裁剪方式在ImageView上也是有的,分别对应ImageView的ImageView.ScaleType.CENTER_CROP和mageView.ScaleType.FIT_CENTER的.

public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);
        targetView.setScaleType(ImageView.ScaleType.FIT_CENTER);
        Glide.with(this).
                load(R.drawable.test).
                placeholder(R.drawable.bg_loading).//加载中显示的图片
                error(R.drawable.bg_error).//加载失败时显示的图片
                crossFade(1000).//淡入淡出,注意:如果设置了这个,则必须要去掉asBitmap
                override(80,80).//设置最终显示的图片像素为80*80,注意:这个是像素,而不是控件的宽高
                centerCrop().//中心裁剪,缩放填充至整个ImageView
                into(targetView);
    }
}

11.缓存策略设置

内存缓存设置,通过skipMemoryCache(boolean)来设置是否需要缓存到内存,默认是会缓存到内存的.

/**
 * Created by mChenys on 2016/6/6.
 */
public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);
        targetView.setScaleType(ImageView.ScaleType.FIT_CENTER);
        Glide.with(this).
                load(R.drawable.test).
                placeholder(R.drawable.bg_loading).//加载中显示的图片
                error(R.drawable.bg_error).//加载失败时显示的图片
                crossFade(1000).//淡入淡出,注意:如果设置了这个,则必须要去掉asBitmap
                override(80,80).//设置最终显示的图片像素为80*80,注意:这个是像素,而不是控件的宽高
                centerCrop().//中心裁剪,缩放填充至整个ImageView
                skipMemoryCache(true).//跳过内存缓存
                into(targetView);
    }
}

磁盘缓存,磁盘缓存通过diskCacheStrategy(DiskCacheStrategy)来设置,DiskCacheStrategy一共有4种模式:

  • DiskCacheStrategy.NONE:什么都不缓存
  • DiskCacheStrategy.SOURCE:仅缓存原图(全分辨率的图片)
  • DiskCacheStrategy.RESULT:仅缓存最终的图片,即修改了尺寸或者转换后的图片
  • DiskCacheStrategy.ALL:缓存所有版本的图片,默认模式
public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);
        targetView.setScaleType(ImageView.ScaleType.FIT_CENTER);
        Glide.with(this).
                load(R.drawable.test).
                placeholder(R.drawable.bg_loading).//加载中显示的图片
                error(R.drawable.bg_error).//加载失败时显示的图片
                crossFade(1000).//淡入淡出,注意:如果设置了这个,则必须要去掉asBitmap
                override(80, 80).//设置最终显示的图片像素为80*80,注意:这个是像素,而不是控件的宽高
                centerCrop().//中心裁剪,缩放填充至整个ImageView
                skipMemoryCache(true).//跳过内存缓存
                diskCacheStrategy(DiskCacheStrategy.RESULT).//保存最终图片
                into(targetView);
    }
}

12.缓存设置

在GlideModule 中,我们可以设置磁盘缓存的位置,磁盘缓存的大小和内存缓存的大小,同时还可以设置图片的显示质量.

要是用GlideModule ,需要创建它的实现类,然后在manifests中申明实现类的全类路径:

<meta-data
          android:name="com.example.mchenys.httputilsdemo.image.glide.module.SimpleGlideModule"
          android:value="GlideModule" />

GlideModule 的实现类,需要实现applyOptions方法:

/**
 * 所以你知道要创建一个额外的类去定制 Glide。
 * 下一步是要全局的去声明这个类,让 Glide 知道它应该在哪里被加载和使用。
 * Glide 会扫描 AndroidManifest.xml 为 Glide module 的 meta 声明。
 * 因此,你必须在 AndroidManifest.xml 的 <application> 标签内去声明这个SimpleGlideModule。
 * Created by mChenys on 2016/6/10.
 */
public class SimpleGlideModule implements GlideModule {
    public static DiskCache cache;

    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        // 在 Android 中有两个主要的方法对图片进行解码:ARGB8888 和 RGB565。前者为每个像素使用了 4 个字节,
        // 后者仅为每个像素使用了 2 个字节。ARGB8888 的优势是图像质量更高以及能存储一个 alpha 通道。
        // Picasso 使用 ARGB8888,Glide 默认使用低质量的 RGB565。
        // 对于 Glide 使用者来说:你使用 Glide module 方法去改变解码规则。
        builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
        //设置缓存目录
        File cacheDir = PathUtils.getDiskCacheDir(context, CacheConfig.IMG_DIR);

        cache = DiskLruCacheWrapper.get(cacheDir, DiskCache.Factory.DEFAULT_DISK_CACHE_SIZE);// 250 MB
        builder.setDiskCache(new DiskCache.Factory() {
            @Override
            public DiskCache build() {
                return cache;
            }
        });
        //设置memory和Bitmap池的大小
        MemorySizeCalculator calculator = new MemorySizeCalculator(context);
        int defaultMemoryCacheSize = calculator.getMemoryCacheSize();
        int defaultBitmapPoolSize = calculator.getBitmapPoolSize();

        int customMemoryCacheSize = (int) (1.2 * defaultMemoryCacheSize);
        int customBitmapPoolSize = (int) (1.2 * defaultBitmapPoolSize);

        builder.setMemoryCache(new LruResourceCache(customMemoryCacheSize));
        builder.setBitmapPool(new LruBitmapPool(customBitmapPoolSize));
    }

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

13.设置图片请求的优先级

Glide 可以用 Priority 枚举来设置图片的加载优先级,这样我们就可以针对那些需要显示的图片设置高的优先级了.

Priority 有4种级别:

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

例如:

/**
    * 高优先级加载
    * @param url
    * @param imageView
    * @param listener
    */
   public static void loadImageWithHighPriority(Object url,ImageView imageView, final LoaderListener listener) {
       if (url == null) {
           if (listener != null) {
               listener.onError();
           }
       } else {
           Glide.with(imageView.getContext()).
                   load(url).
                   asBitmap().
                   priority(Priority.HIGH).//高优先级
                   dontAnimate().
                   listener(new RequestListener<Object, Bitmap>() {
                       @Override
                       public boolean onException(Exception e, Object model, Target<Bitmap> target, boolean isFirstResource) {
                           if (null != listener) {
                               listener.onError();
                           }
                           return false;
                       }

                       @Override
                       public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {
                           if (null != listener) {
                               listener.onSuccess();
                           }
                           return false;
                       }
                   }).into(imageView);
       }
   }

14.设置加载缩略图

通过设置缩略图,我们可以在显示目标图片之前先展示一个第分辨率或者其他图片,当全分辨率的目标图片在后台加载完成后,
Glide会自动切换显示全像素的目标图片.

设置缩略图有2种方式:
通过thumbnail(float)指定0.0f~1.0f的原始图像大小,例如全像素的大小是500500,如果设置为thumbnail为0.1f,即目标图片的10%,显示的缩略图大小就是5050;

public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);

        Glide.with(this).
                load(R.drawable.test).
                placeholder(R.drawable.bg_loading).//加载中显示的图片
                error(R.drawable.bg_error).//加载失败时显示的图片
                crossFade(1000).//淡入淡出,注意:如果设置了这个,则必须要去掉asBitmap
                override(80, 80).//设置最终显示的图片像素为80*80,注意:这个是像素,而不是控件的宽高
                centerCrop().//中心裁剪,缩放填充至整个ImageView
                skipMemoryCache(true).//跳过内存缓存
                diskCacheStrategy(DiskCacheStrategy.RESULT).//保存最终图片
                thumbnail(0.1f).//10%的原图大小
                into(targetView);
    }
}

通过thumbnail(DrawableRequestBuilder)方式来指定缩略图,该缩略图可以使用load的所有方式(网络,文件,uri,资源)加载.

public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);
        //缩略图请求
        DrawableRequestBuilder<String> thumbnailRequest = Glide
                .with(this)
                .load("http://www.qq745.com/uploads/allimg/141106/1-141106153Q5.png");

        Glide.with(this).
                load(R.drawable.test).
//                placeholder(R.drawable.bg_loading).//加载中显示的图片
//                error(R.drawable.bg_error).//加载失败时显示的图片
//                crossFade(1000).//淡入淡出,注意:如果设置了这个,则必须要去掉asBitmap
                override(80, 80).//设置最终显示的图片像素为80*80,注意:这个是像素,而不是控件的宽高
                centerCrop().//中心裁剪,缩放填充至整个ImageView
                skipMemoryCache(true).//跳过内存缓存
                diskCacheStrategy(DiskCacheStrategy.RESULT).//保存最终图片
                thumbnail(thumbnailRequest).//设置缩略图
                into(targetView);
    }
}

15.Transformations Bitmap

在显示目标图片之前,我们可以对目标图片的Bitmap进行相应的处理,例如::圆角图片,圆形图片,高斯模糊,旋转,灰度等等.
只需要实现Transformation接口即可,该接口的transform方法会返回显示图片前的Bitmap对象,在该方法中对
Bitmap的任何处理,都会影响到最终的显示结果.
当然,如果你只是想要对图片做常规的 bitmap 转换,你可以继承抽象类BitmapTransformation,它简化了Transformation接口的实现,这应该能覆盖大部分的应用场景了。

使用的时候,通过transform(Transformation… transformations)来设置.例如:

public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);
        Glide.with(this).
                load(R.drawable.test).
                asBitmap().
                transform(new BlurTransformation(this)).//高斯模糊处理
                into(targetView);
    }
}

下面贴出常用的几个Bitmap的转换处理的代码,在github上也有glide-transformations-master库.

圆图处理

public class CropCircleTransformation implements Transformation<Bitmap> {

    private BitmapPool mBitmapPool;

    public CropCircleTransformation(Context context) {
        this(Glide.get(context).getBitmapPool());
    }

    public CropCircleTransformation(BitmapPool pool) {
        this.mBitmapPool = pool;
    }

    @Override
    public Resource<Bitmap> transform(Resource<Bitmap> resource, int outWidth, int outHeight) {
        Bitmap source = resource.get();
        int size = Math.min(source.getWidth(), source.getHeight());

        int width = (source.getWidth() - size) / 2;
        int height = (source.getHeight() - size) / 2;

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

        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint();
        BitmapShader shader =
                new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
        if (width != 0 || height != 0) {
            // source isn't square, move viewport to center
            Matrix matrix = new Matrix();
            matrix.setTranslate(-width, -height);
            shader.setLocalMatrix(matrix);
        }
        paint.setShader(shader);
        paint.setAntiAlias(true);

        float r = size / 2f;
        canvas.drawCircle(r, r, r, paint);

        return BitmapResource.obtain(bitmap, mBitmapPool);
    }

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

圆角处理

public class RoundedCornersTransformation implements Transformation<Bitmap> {

    private BitmapPool mBitmapPool;

    private int radius;
    private int margin;

    public RoundedCornersTransformation(Context context, int radius, int margin) {
        this(Glide.get(context).getBitmapPool(), radius, margin);
    }

    public RoundedCornersTransformation(BitmapPool pool, int radius, int margin) {
        mBitmapPool = pool;
        this.radius = radius;
        this.margin = margin;
    }

    @Override
    public Resource<Bitmap> transform(Resource<Bitmap> resource, int outWidth, int outHeight) {
        Bitmap source = resource.get();

        int width = source.getWidth();
        int height = source.getHeight();

        Bitmap bitmap = mBitmapPool.get(width, height, Bitmap.Config.ARGB_8888);
        if (bitmap == null) {
            bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
        canvas.drawRoundRect(new RectF(margin, margin, width - margin, height - margin), radius, radius,
                paint);

        return BitmapResource.obtain(bitmap, mBitmapPool);
    }

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

灰度处理

public class GrayscaleTransformation implements Transformation<Bitmap> {

    private BitmapPool mBitmapPool;

    public GrayscaleTransformation(Context context) {
        this(Glide.get(context).getBitmapPool());
    }

    public GrayscaleTransformation(BitmapPool pool) {
        mBitmapPool = pool;
    }

    @Override
    public Resource<Bitmap> transform(Resource<Bitmap> resource, int outWidth, int outHeight) {
        Bitmap source = resource.get();

        int width = source.getWidth();
        int height = source.getHeight();

        Bitmap.Config config =
                source.getConfig() != null ? source.getConfig() : Bitmap.Config.ARGB_8888;
        Bitmap bitmap = mBitmapPool.get(width, height, config);
        if (bitmap == null) {
            bitmap = Bitmap.createBitmap(width, height, config);
        }

        Canvas canvas = new Canvas(bitmap);
        ColorMatrix saturation = new ColorMatrix();
        saturation.setSaturation(0f);
        Paint paint = new Paint();
        paint.setColorFilter(new ColorMatrixColorFilter(saturation));
        canvas.drawBitmap(source, 0, 0, paint);

        return BitmapResource.obtain(bitmap, mBitmapPool);
    }

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

旋转处理

public class RotateTransformation extends BitmapTransformation {

    private float rotateRotationAngle = 0f;

    public RotateTransformation(Context context, float rotateRotationAngle) {
        super(context);

        this.rotateRotationAngle = rotateRotationAngle;
    }

    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        Matrix matrix = new Matrix();

        matrix.postRotate(rotateRotationAngle);

        return Bitmap.createBitmap(toTransform, 0, 0, toTransform.getWidth(), toTransform.getHeight(), matrix, true);
    }

    @Override
    public String getId() {
        return "rotate" + rotateRotationAngle;
    }
}

高斯模糊处理

public class BlurTransformation implements Transformation<Bitmap> {

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

    private Context mContext;
    private BitmapPool mBitmapPool;

    private int mRadius;
    private int mSampling;

    public BlurTransformation(Context context) {
        this(context, Glide.get(context).getBitmapPool(), MAX_RADIUS, DEFAULT_DOWN_SAMPLING);
    }

    public BlurTransformation(Context context, BitmapPool pool) {
        this(context, pool, MAX_RADIUS, DEFAULT_DOWN_SAMPLING);
    }

    public BlurTransformation(Context context, BitmapPool pool, int radius) {
        this(context, pool, radius, DEFAULT_DOWN_SAMPLING);
    }

    public BlurTransformation(Context context, int radius) {
        this(context, Glide.get(context).getBitmapPool(), radius, DEFAULT_DOWN_SAMPLING);
    }

    public BlurTransformation(Context context, BitmapPool pool, int radius, int sampling) {
        mContext = context;
        mBitmapPool = pool;
        mRadius = radius;
        mSampling = sampling;
    }

    public BlurTransformation(Context context, int radius, int sampling) {
        mContext = context;
        mBitmapPool = Glide.get(context).getBitmapPool();
        mRadius = radius;
        mSampling = sampling;
    }

    @Override
    public Resource<Bitmap> transform(Resource<Bitmap> resource, int outWidth, int outHeight) {
        Bitmap source = resource.get();

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

        Bitmap bitmap = mBitmapPool.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);
        }

        return BitmapResource.obtain(bitmap, mBitmapPool);
    }

    @Override public String getId() {
        return "BlurTransformation(radius=" + mRadius + ", sampling=" + mSampling + ")";
    }
}

网上提供的FastBlur,可兼容低版本的高斯模糊处理

public class FastBlur {

    public static Bitmap blur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap) {

        Bitmap bitmap;
        if (canReuseInBitmap) {
            bitmap = sentBitmap;
        } else {
            bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
        }

        if (radius < 1) {
            return (null);
        }

        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        int[] pix = new int[w * h];
        bitmap.getPixels(pix, 0, w, 0, 0, w, h);

        int wm = w - 1;
        int hm = h - 1;
        int wh = w * h;
        int div = radius + radius + 1;

        int r[] = new int[wh];
        int g[] = new int[wh];
        int b[] = new int[wh];
        int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
        int vmin[] = new int[Math.max(w, h)];

        int divsum = (div + 1) >> 1;
        divsum *= divsum;
        int dv[] = new int[256 * divsum];
        for (i = 0; i < 256 * divsum; i++) {
            dv[i] = (i / divsum);
        }

        yw = yi = 0;

        int[][] stack = new int[div][3];
        int stackpointer;
        int stackstart;
        int[] sir;
        int rbs;
        int r1 = radius + 1;
        int routsum, goutsum, boutsum;
        int rinsum, ginsum, binsum;

        for (y = 0; y < h; y++) {
            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
            for (i = -radius; i <= radius; i++) {
                p = pix[yi + Math.min(wm, Math.max(i, 0))];
                sir = stack[i + radius];
                sir[0] = (p &amp; 0xff0000) >> 16;
                sir[1] = (p &amp; 0x00ff00) >> 8;
                sir[2] = (p &amp; 0x0000ff);
                rbs = r1 - Math.abs(i);
                rsum += sir[0] * rbs;
                gsum += sir[1] * rbs;
                bsum += sir[2] * rbs;
                if (i > 0) {
                    rinsum += sir[0];
                    ginsum += sir[1];
                    binsum += sir[2];
                } else {
                    routsum += sir[0];
                    goutsum += sir[1];
                    boutsum += sir[2];
                }
            }
            stackpointer = radius;

            for (x = 0; x < w; x++) {

                r[yi] = dv[rsum];
                g[yi] = dv[gsum];
                b[yi] = dv[bsum];

                rsum -= routsum;
                gsum -= goutsum;
                bsum -= boutsum;

                stackstart = stackpointer - radius + div;
                sir = stack[stackstart % div];

                routsum -= sir[0];
                goutsum -= sir[1];
                boutsum -= sir[2];

                if (y == 0) {
                    vmin[x] = Math.min(x + radius + 1, wm);
                }
                p = pix[yw + vmin[x]];

                sir[0] = (p &amp; 0xff0000) >> 16;
                sir[1] = (p &amp; 0x00ff00) >> 8;
                sir[2] = (p &amp; 0x0000ff);

                rinsum += sir[0];
                ginsum += sir[1];
                binsum += sir[2];

                rsum += rinsum;
                gsum += ginsum;
                bsum += binsum;

                stackpointer = (stackpointer + 1) % div;
                sir = stack[(stackpointer) % div];

                routsum += sir[0];
                goutsum += sir[1];
                boutsum += sir[2];

                rinsum -= sir[0];
                ginsum -= sir[1];
                binsum -= sir[2];

                yi++;
            }
            yw += w;
        }
        for (x = 0; x < w; x++) {
            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
            yp = -radius * w;
            for (i = -radius; i <= radius; i++) {
                yi = Math.max(0, yp) + x;

                sir = stack[i + radius];

                sir[0] = r[yi];
                sir[1] = g[yi];
                sir[2] = b[yi];

                rbs = r1 - Math.abs(i);

                rsum += r[yi] * rbs;
                gsum += g[yi] * rbs;
                bsum += b[yi] * rbs;

                if (i > 0) {
                    rinsum += sir[0];
                    ginsum += sir[1];
                    binsum += sir[2];
                } else {
                    routsum += sir[0];
                    goutsum += sir[1];
                    boutsum += sir[2];
                }

                if (i < hm) {
                    yp += w;
                }
            }
            yi = x;
            stackpointer = radius;
            for (y = 0; y < h; y++) {
                // Preserve alpha channel: ( 0xff000000 &amp; pix[yi] )
                pix[yi] = (0xff000000 &amp; pix[yi]) | (dv[rsum] < 16) | (dv[gsum] < 8) | dv[bsum];

                rsum -= routsum;
                gsum -= goutsum;
                bsum -= boutsum;

                stackstart = stackpointer - radius + div;
                sir = stack[stackstart % div];

                routsum -= sir[0];
                goutsum -= sir[1];
                boutsum -= sir[2];

                if (x == 0) {
                    vmin[y] = Math.min(y + r1, hm) * w;
                }
                p = x + vmin[y];

                sir[0] = r[p];
                sir[1] = g[p];
                sir[2] = b[p];

                rinsum += sir[0];
                ginsum += sir[1];
                binsum += sir[2];

                rsum += rinsum;
                gsum += ginsum;
                bsum += binsum;

                stackpointer = (stackpointer + 1) % div;
                sir = stack[stackpointer];

                routsum += sir[0];
                goutsum += sir[1];
                boutsum += sir[2];

                rinsum -= sir[0];
                ginsum -= sir[1];
                binsum -= sir[2];

                yi += w;
            }
        }

        bitmap.setPixels(pix, 0, w, 0, 0, w, h);

        return (bitmap);
    }
}

RenderScript处理高斯模糊

android4.3之后可使用,需要在build.gradle中配置:

defaultConfig {
    //BlurTransformation
    renderscriptTargetApi 23
    renderscriptSupportModeEnabled true
}
public class RSBlur {

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
    public static Bitmap blur(Context context, Bitmap blurredBitmap, int radius) throws RSRuntimeException {
        try {
            RenderScript rs = RenderScript.create(context);
            Allocation input = Allocation.createFromBitmap(rs, blurredBitmap, Allocation.MipmapControl.MIPMAP_NONE,
                    Allocation.USAGE_SCRIPT);
            Allocation output = Allocation.createTyped(rs, input.getType());
            ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));

            blur.setInput(input);
            blur.setRadius(radius);
            blur.forEach(output);
            output.copyTo(blurredBitmap);
            rs.destroy();
        } catch (RSRuntimeException e) {
            blurredBitmap = FastBlur.blur(blurredBitmap, radius, true);
        }
        return blurredBitmap;
    }
}

16.动画处理

通过animate()方法可以设置xml文件定义的4种补间动画(alpha、scale、translate、rotate)
例如:

res\anim\left_in.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromXDelta="-50%p"
        android:toXDelta="0"/>
    <alpha
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromAlpha="0.0"
        android:toAlpha="1.0"/>
</set>

使用方式:

public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);
        Glide.with(this).
                load(R.drawable.test).
                asBitmap().
                animate(R.anim.left_in).//加载xml文件定义的动画
                into(targetView);
    }
}

处理此外,还可以通过animate指定属性动画:

 public class TestGlideActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        ImageView targetView = (ImageView) findViewById(R.id.iv_target);

        ViewPropertyAnimation.Animator animationObject = new ViewPropertyAnimation.Animator() {
            @Override
            public void animate(View view) {
                //设置属性动画
                ObjectAnimator moveIn = ObjectAnimator.ofFloat(view, "translationX", -500f, 0f);
                ObjectAnimator rotate = ObjectAnimator.ofFloat(view, "rotation", 0f, 360f);
                ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f, 1f);
                ObjectAnimator moveTop = ObjectAnimator.ofFloat(view, "translationY", 0f, -2000, 0f);
                AnimatorSet animSet = new AnimatorSet();
                //先左进,然后旋转伴随淡入效果,最后移动向上
                animSet.play(rotate).with(fadeInOut).after(moveIn).before(moveTop);
                animSet.setDuration(5000);
                animSet.start();
            }
        };
        Glide.with(this).
                load(R.drawable.test).
                asBitmap().
                animate(animationObject).//加载属性动画
                into(targetView);
    }
}

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

17.回调: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。  

18.调试和错误处理

可以使用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()回调。

19.集成自己的网络库

你可以使用自己的网络库,但这个细讲起来还比较复杂。这里介绍当你的工程使用的是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'
}

摘录来源