Android开发中使用Glide V4 中Generated API特性_新根的博客-程序员宅基地

技术标签: android开发  Android 热门的框架与第三方SDK  Glide V4 图片加载库  Android 应用层开发  Glide框架  GlideApp  Glidev4  

Android Glide4 异步图片框架

实战项目案例


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。

@GlideModule
public 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明确清除先前的加载,以防加载到旧数据。

@Override
public 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

资源汇总

问题汇总:


  • 在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)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hexingen/article/details/72579529

智能推荐

PTA 6-19单链表结点删除_「已注销」的博客-程序员宅基地_在上述程序基础上,实现删除某结点功能

6-19 单链表结点删除 (20分)本题要求实现两个函数,分别将读入的数据存储为单链表、将链表中所有存储了某给定值的结点删除。链表结点定义如下:struct ListNode {int data;ListNode *next;};函数接口定义:struct ListNode *readlist();struct ListNode *deletem( struct ListNode ...

JAVA tomcat 配置jndi而且使用c3p0连接池_Uncle的博客-程序员宅基地

配置MYSQL 的JNDI采取的方式时再META-INF文件夹下创建context.xml配置应用的jndi。优点每个应用独立JNDI.配置文件及其步骤如下:1、META-INF中创建 <Resource name="jdbc/mysql" auth="Container" factory="org.apache.naming.f

AttributeError: ‘LSTM‘ object has no attribute ‘proj_size‘原因和解决办法_zy_ky的博客-程序员宅基地_如何更改proj_size

之前训练好的pytrorch模型现在重新打开就报错。报错为:AttributeError: 'LSTM' object has no attribute 'proj_size'开始我还以为是程序哪里错了,不科学啊,搜中文网站搜不到任何信息,用谷歌搜到了,链接如下:https://github.com/flairNLP/flair/issues/2137原因就是pytorch1.8版本的RNN系列函数都有问题,不能和之前的版本训练的模型兼容。到底有什么错,不清楚,1.8版本训练的模型能和1.7兼容吗

解决Centos7 yum 出现could not retrieve mirrorlist 错误_北桥苏的博客-程序员宅基地

刚通过VMware12安装了centos7.x后,使用ip addr查看centos局域网的ip发现没有,使用yum安装一些工具包时也出现报错:Loaded plugins: fastestmirror, refresh-packagekit, securityLoading mirror speeds from cached hostfileCould not retrieve mi...

Spring(四)-- JdbcTemplate_Mr.OO的博客-程序员宅基地_beanpropertyrowmapper<account>(account.class) .cla

JdbcTemplate实现 jdbctemplate 要导入的依赖&lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-context&lt;/artifactId&gt; &lt;...

面试官:说说Ribbon是如何实现负载均衡的?_业余草的博客-程序员宅基地

你知道的越多,不知道的就越多,业余的像一棵小草!你来,我们一起精进!你不来,我和你的竞争对手一起精进!编辑:业余草来源:blog.csdn.net/LO_YUN/article/deta...

随便推点

【CMake 语法】(4) CMake 命令、命令参数、转义序列_exuan00的博客-程序员宅基地_cmake 转义

1. 命令CMake 源码文件基本上由命令组成。2. 命令参数命令调用中由三种类型的参数:括号参数带引号的参数不带引号的参数括号参数括号参数内容,是左括号 [ 跟零个或多个 = 以右括号 ] 结束。括号参数,不执行 转义序列 或 变量引用。例如:message([=[This is the first line in a bracket argument with bracket length 1.No \-escape sequences or ${variable} r

ASP.NET 登录控件概述_apinghappy的博客-程序员宅基地_登录控件与 什么和什么 集成了一样

ASP.NET 登录控件概述 众多 ASP.NET 登录控件一起为 ASP.NET Web 应用程序提供可靠的无需编程的登录解决方案。默认情况下,登录控件与 ASP.NET 成员资格和 Forms 身份验证集成,以帮助使网站的用户身份验证过程自动化。有关将 ASP.NET 成员资格与 Forms 身份验证一起使用的信息,请参见成员资格介绍。默认情况下,ASP.NET 登录控

【Web安全笔记】之【2.0 计算机网络与协议】_AA8j的博客-程序员宅基地

2.0 计算机网络与协议2.1 网络基础计算机通信网的组成计算机网络由通信子网和资源子网组成。其中通信子网负责数据的无差错和有序传递,其处理功能包括差错控制、流量控制、路由选择、网络互连等。其中资源子网是计算机通信的本地系统环境,包括主机、终端和应用程序等, 资源子网的主要功能是用户资源配置、数据的处理和管理、软件和硬件共享以及负载均衡等。总的来说,计算机通信网就是一个由通信子网承载的、传输和共享资源子网的各类信息的系统。通信协议为了完成计算机之间有序的信息交换,提出了通信协议的概念,其定义

【小白入门】记录计算机语言相关应用知识_期邈云汉的博客-程序员宅基地_计算机各语言的应用小白

一. 系统(软件)——— 驱动程序C/C++二. C\S架构软件Client客户(用户)端Server服务端(器) C/C++ C#sharp QT:Adobe LOL客户端 暴雪 极品飞车········三. B\S架构软件(网站)B:浏览器S:服务器 *前端:HTML CSS JS* *后端: JAVA PHP* 移动端:Android Java KotlinIOS

二分法解题思路_-Billy的博客-程序员宅基地

二分法的精髓:函数的单调性 +  计算内容重复 (注意:不同于分治)根据区间范围,猜测答案的结果。 1. Sqrt(x)求平方根 public int mySqrt(int y) { int left = 0; int right = y; long mid = 0; // 区间范围[0, y] while (left &amp;lt;= right) { ...

RAID2.0+技术亮点_小段学长的博客-程序员宅基地

RAID 2.0+技术特征RAID 2.0+技术在RAID 2.0的基础上提供了更细粒度(可以达几十KB粒度)的资源颗粒,形成存储资源的标准分配及回收单位,类似计算虚拟化中的虚拟机,我们称之为虚拟块。这些容量单位一致的虚拟块构成了一个统一的存储资源池,所有应用、中间件、虚拟机、操作系统所需的资源可以在这个资源池中按需分配及回收。相对传统RAID系统,RAID2.0+技术实现了存储资源的虚拟化及预配置,存储资源的申请及释放完全自动化的通过存储池实现,而不再需要传统RAID阵列的RAID组创建,LUN创建,

推荐文章

热门文章

相关标签