Android开发中使用Glide V4 中Generated API特性

来源:互联网 发布:学java入门什么书推建 编辑:程序博客网 时间:2024/05/20 11:35

Android Glide4 异步图片框架

  • 简介篇: Glide框架

  • 迁移篇:Glide V4 框架新特性(Migrating from v3 to v4)

  • 基础篇:Android开发中使用Glide V4 中Generated API特性

  • 常用篇:Android Glide设置默认图片、异常图片为圆形图片

  • 进级篇:Kotlin编程开发之Glide V4使用OkHttp3作为传输层

实战项目案例

  • Kotlin Android Extensions+Android MVP项目(RxJava+Rerotfit+OkHttp+Glide)
  • Anko Layout+MVP(Glide,Retrofit,OkHttp,RxJava)开发Android运用程序

Google在2013年发布了网络文本和图片异步加载的Volley框架,而在2014年的Google IO app中推举Glide框架来加载图片。这说明,Glide比起Volley中ImageRequst更具备优势,节省内存和节省宽带数据。

这里,Volley框架和Glide框架用加载同样的网络资源,进行比较了一番。

RecyclerView中使用Volley的NetWorkImageView的内存情况:

这里写图片描述

RecyclerView中ImageView使用Glide的内存情况:

这里写图片描述

若是不熟悉Glide框架使用情况,可以阅读Glide 框架和Glide v4新特性。

使用Glide v4中的Generated API 开发


前期配置,在项目中Gradle中引入库的依赖

dependencies {    compile fileTree(include: ['*.jar'], dir: 'libs')    testCompile 'junit:junit:4.12'    compile 'com.android.support:appcompat-v7:25.3.1'    compile 'com.android.support:design:25.3.1'    compile 'com.android.support:recyclerview-v7:25.3.1'    //Glide框架引入    compile 'com.github.bumptech.glide:glide:4.0.0-RC0'    annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0-RC0'}

自定义AppGlideModule

为运用程序定义一个带有@GlideModule注解的AppGlideModule,运用程序会使用和AppGlideMoudle同一个包下的GlideApp类。通过GlideApp.with()方式使用Glide的Generated API。

@GlideModulepublic final class CustomAppGlideModule extends AppGlideModule{    /**     *  通过GlideBuilder设置默认的结构(Engine,BitmapPool ,ArrayPool,MemoryCache等等).     * @param context     * @param builder     */    @Override    public void applyOptions(Context context, GlideBuilder builder) {         //重新设置内存限制         builder.setMemoryCache(new LruResourceCache(10*1024*1024));    }    /**     * 为App注册一个自定义的String类型的BaseGlideUrlLoader     *     * @param context     * @param registry     */    @Override    public void registerComponents(Context context, Registry registry) {             registry.append(String.class, InputStream.class,new CustomBaseGlideUrlLoader.Factory());    }    /**     * 清单解析的开启     *     * 这里不开启,避免添加相同的modules两次     * @return     */    @Override    public boolean isManifestParsingEnabled() {        return false;    }}

注意点

  1. 必需带有@GlideModule注解。
  2. isManifestParsingEnabled() 返回false,关闭解析AndroidManifest,不需要再配置GlideModule.

自定义BaseGlideUrlLoader

根据带有图片尺寸的URl,来获取合适比例的图片资源。通过指定String类型的Model, BaseGliUrlLOader中getgetURL()来覆盖原本的带有http或者htpps的URL. 这里处理方式来源于,Google IO App.

public class CustomBaseGlideUrlLoader extends BaseGlideUrlLoader<String> {    private static final ModelCache<String, GlideUrl> urlCache =            new ModelCache<>(150);    /**     * Url的匹配规则     */    private static final Pattern PATTERN = Pattern.compile("__w-((?:-?\\d+)+)__");    public CustomBaseGlideUrlLoader(ModelLoader<GlideUrl, InputStream> concreteLoader,ModelCache<String, GlideUrl> modelCache) {        super(concreteLoader,modelCache);    }    /**     * If the URL contains a special variable width indicator (eg "__w-200-400-800__")     * we get the buckets from the URL (200, 400 and 800 in the example) and replace     * the URL with the best bucket for the requested width (the bucket immediately     * larger than the requested width).     *     * 控制加载的图片的大小     */    @Override    protected String getUrl(String model, int width, int height, Options options) {        Matcher m = PATTERN.matcher(model);        int bestBucket = 0;        if (m.find()) {            String[] found = m.group(1).split("-");            for (String bucketStr : found) {                bestBucket = Integer.parseInt(bucketStr);                if (bestBucket >= width) {                    // the best bucket is the first immediately bigger than the requested width                    break;                }            }            if (bestBucket > 0) {                model = m.replaceFirst("w"+bestBucket);            }        }        return model;    }    @Override    public boolean handles(String s) {        return true;    }    /**     * 工厂来构建CustormBaseGlideUrlLoader对象     */    public static class Factory implements ModelLoaderFactory<String,InputStream>{        @Override        public ModelLoader<String, InputStream> build(MultiModelLoaderFactory multiFactory) {            return new CustomBaseGlideUrlLoader(multiFactory.build(GlideUrl.class,InputStream.class),urlCache);        }        @Override        public void teardown() {        }    }}

ProGuard Rules中添加混淆规则

根据上面的自定义,保持AppGlideModule子类和GlideModule实现类不被混淆。

#Glide的混淆规则-keep public class * implements com.bumptech.glide.module.GlideModule-keep public class * extends com.bumptech.glide.AppGlideModule-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {    **[] $VALUES;    public *;}

使用权限 : 联网权限,读写权限,AndroidManifest.xml中自行配置。

确保GlideApp类正常引用

当配置完以上步骤后,发觉不能使用GlideApp类。

解决方式:在AndroidStudio中Build–>Make Project

–>将会出现build/generated/source中,便可以使用GlideApp

使用GlideApp类用于各种场景


1. 单个ImageView加载图像资源

Url:https://www.baidu.com/img/bd_logo1.png

Uri:content://media/external/images/1

Resource Id :R.drawable.image或者R.mipmap.ic_launcher

当然,还有其他的图像资源。

加载本地图片

    /**     * 加载本地图片,这里是mipmap文件夹下的资源     */    private void loadLocalImage() {        RequestBuilder<Drawable> drawableRequestBuilder = GlideApp.with(this).load(R.mipmap.ic_launcher);        drawableRequestBuilder.into(this.local_iv);    }

加载网络图片

    /**     * 从远程网路上加载图片     */    private void loadRemoteImage() {        GlideApp.with(this).asBitmap()        .load(ImageResouce.imageResource[0])        .error(R.mipmap.ic_launcher)//占位图片        .placeholder(R.mipmap.ic_launcher)//异常图片        .into(this.remote_iv);    }

预先下载,本地缓存中加载

    /**     * 预先加载资源     */    private void startPreload() {        GlideApp.with(this).asBitmap()                .load(ImageResouce.imageResource[1])                .diskCacheStrategy(DiskCacheStrategy.ALL)                .preload();    }    /**     * 预先下载原始图片资源后,本地加载     */    private void loadPreloadImage() {        GlideApp.with(this).asBitmap().load(ImageResouce.imageResource[1]).diskCacheStrategy(DiskCacheStrategy.ALL).into(this.preload_iv);    }

error 和placeholder的处理

    .error(R.mipmap.ic_launcher) //异常图片    .placeholder(R.mipmap.ic_launcher) //占位图片    .fallback(R.mipmap.ic_launcher); //当url为空时,回调显示的图片

2. RecyclerView(或者ListView,GridView)中加载图片资源

Glide单一要求是任何重复使用的View Target,调用Clear()API明确清除先前的加载,以防加载到旧数据。

@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {        ImageView imageView=holder.getImageView();         String url=imageList.get(position);        if(TextUtils.isEmpty(url)){            //清空旧数据的引用            GlideApp.with(context).clear(imageView);            //当资源为空时候,设置默认图片            imageView.setImageResource(R.mipmap.ic_launcher);        }else{//开启一个图片加载            loadImage(url,imageView);        }}    /**     * 加载图片     * @param url     * @param imageView     */public void loadImage(String url,ImageView imageView){       RequestBuilder<Bitmap> bitmapRequestBuilder= GlideApp.with(context)               .asBitmap()//指定Bitmap类型的RequestBuilder               .load(url)//网络URL               .error(R.mipmap.ic_launcher)//异常图片               .placeholder(R.mipmap.ic_launcher)//占位图片               .fallback(R.mipmap.ic_launcher);//当url为空时,显示图片        bitmapRequestBuilder.into(imageView);}

3. 自定义Circle Transformation 实现圆角图片

Glide拥有两个默认的转换(transformation):

  • Fit center:类似Android’s ScaleType.FIT_CENTER
  • Center crop:类似Android’s ScaleType.CENTER_CROP

这里继承BitmapTransformation,复写transform()

public class CircleTransform extends BitmapTransformation{    public CircleTransform(Context context){        super(context);    }    /**     *  重写 生成圆角图片     * @param pool     * @param toTransform     * @param outWidth     * @param outHeight     * @return     */    @Override    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {        return circleCrop(pool,toTransform);    }    private static 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;        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 void updateDiskCacheKey(MessageDigest messageDigest) {    }}

Glide使用自定义的Transform,最后将圆形Bitmap加载到ImageView上:

    /**     * 加载图片     * @param url     * @param imageView     */    public void loadImage(String url,ImageView imageView){       RequestBuilder<Bitmap> bitmapRequestBuilder= GlideApp.with(context)               .asBitmap()//指定Bitmap类型的RequestBuilder               .load(url)//网络URL               .error(R.mipmap.ic_launcher)//异常图片               .placeholder(R.mipmap.ic_launcher)//占位图片               .fallback(R.mipmap.ic_launcher);//当url为空时,显示图片        RequestOptions requestOptions=new RequestOptions();        //在RequestOptions中使用Transformations        requestOptions.transform(new CircleTransform(context));        //RequestBuilder<Bitmap> 中添加RequestOptions        bitmapRequestBuilder.apply(requestOptions).into(imageView);    }

4. 自定义BitmapImageViewTarget实现圆角图片

自定义一个BitmapImageViewTarget,复写setResource():

public class CircularBitmapImageViewTarget  extends BitmapImageViewTarget {    private Context context;    private ImageView imageView;    public CircularBitmapImageViewTarget(Context context,ImageView view) {        super(view);        this.context=context;        this.imageView=view;    }    /**     * 重写 setResource(),生成圆角的图片     * @param resource     */    @Override    protected void setResource(Bitmap resource) {        RoundedBitmapDrawable  bitmapDrawable= RoundedBitmapDrawableFactory.create(this.context.getResources(),resource);        /**         *   设置图片的shape为圆形.         *         *   若是需要制定圆角的度数,则调用setCornerRadius()。         */        bitmapDrawable.setCircular(true);        this.imageView.setImageDrawable(bitmapDrawable);    }}

Glide使用自定义ViewTarget:

    /**     * 加载图片     * @param url     * @param imageView     */    public void loadImage(String url,ImageView imageView){       RequestBuilder<Bitmap> bitmapRequestBuilder= GlideApp.with(context)               .asBitmap()//指定Bitmap类型的RequestBuilder               .load(url)//网络URL               .error(R.mipmap.ic_launcher)//异常图片               .placeholder(R.mipmap.ic_launcher)//占位图片               .fallback(R.mipmap.ic_launcher);//当url为空时,显示图片       //在RequestBuilder<Bitmap> 中使用自定义的ImageViewTarget       bitmapRequestBuilder.into(new CircularBitmapImageViewTarget(context,imageView));            }

项目运行效果如下

这里写图片描述

项目代码链接:https://github.com/13767004362/GlideDemo

资源汇总

  • Glide 框架: http://blog.csdn.net/hexingen/article/details/72577453

  • Glide 3.x到4.x的变化:http://blog.csdn.net/hexingen/article/details/72578066

  • Kotlin编程中 Glide V4与OkHttp3自定义集成使用

问题汇总:


  • 在listView或者RecyclerView中使用Glide框架,内存剧增或者爆内存溢出(OutOfMemoryError):

    这里写图片描述

    原因:在ImageView中scaleType使用了fitxy属性:

    <ImageView    android:id="@+id/item_movielist_iv"    android:layout_width="100dp"    android:layout_height="100dp"    android:scaleType="fitXY"/>

    将fitXY改动成:fitCenter 或者centerCrop,内存情况如下:

    这里写图片描述

    解决方式最终来源:https://github.com/bumptech/glide/issues/464

  • 解决同一URL远程图片,多次按不同大小比例加载多次加载的问题:

    Preload Images,将URL对应的数据源即原图保存下载,下次按比例来本地加载:

    diskCacheStrategy(DiskCacheStrategy.ALL)
阅读全文
4 1
原创粉丝点击