zoukankan      html  css  js  c++  java
  • 【Android

    一、Glide简介:

      Glide是Google官方推荐的一个图片加载和缓存的开源库,它不仅能实现平滑的图片列表滚动效果,还支持远程图片的获取、大小调整和展示,并且可以加载GIF图片。Glide相比与UIF、Volley、Picasso、Fresco等其他框架的优点是轻量和稳定。

    二、Glide的配置:

      使用Glide首先需要导入Glide的依赖,在build.gradle文件中添加:

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

      如果Glide需要从网络中加载图片,则还需要在Manifest文件中添加网络访问权限:

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

      Glide为我们提供了一个GlideModule接口,其中提供了一系列Glide配置的抽象方法,我们可以创建一个类实现这个接口,并在实现的方法中设置Glide的一些配置项,如自定义缓存大小和位置、自定义内存和图片池大小、自定义图片格式等。一个GlideModule的实现类样板如下:

    public class GlideConfig implements GlideModule {
        int diskSize = 1024 * 1024 * 100;
        int memorySize = (int) (Runtime.getRuntime().maxMemory()) / 8;  // 取1/8最大内存作为最大缓存
    
        @Override
        public void applyOptions(Context context, GlideBuilder builder) {
            // 定义缓存大小和位置
            builder.setDiskCache(new InternalCacheDiskCacheFactory(context, diskSize));  // 内存中
            // builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, "cache", diskSize)); // sd卡中
    
            // 默认内存和图片池大小
            // MemorySizeCalculator calculator = new MemorySizeCalculator(context);
            // int defaultMemoryCacheSize = calculator.getMemoryCacheSize(); // 默认内存大小
            // int defaultBitmapPoolSize = calculator.getBitmapPoolSize(); // 默认图片池大小
            // builder.setMemoryCache(new LruResourceCache(defaultMemoryCacheSize));
            // builder.setBitmapPool(new LruBitmapPool(defaultBitmapPoolSize));
    
            // 自定义内存和图片池大小
            builder.setMemoryCache(new LruResourceCache(memorySize)); // 自定义内存大小
            builder.setBitmapPool(new LruBitmapPool(memorySize)); // 自定义图片池大小
    
            // 定义图片格式
            // builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
            builder.setDecodeFormat(DecodeFormat.PREFER_RGB_565); // 默认
        }
    
        @Override
        public void registerComponents(Context context, Glide glide) {
        }
    }

      GlideConfig类完成之后,我们需要在Manifest文件中注册这个类,便于Glide找到这个类并进行初始化配置。在Manifest的<application>标签下添加一个<meta-data>标签,在其中注册这个类:

            <!-- 注册Glide的配置文件,以便Glide能够找到 -->
            <meta-data
                android:name="com.example.itgungnir.testglide.GlideConfig"
                android:value="GlideModule" />

      到此为止,Glide的基础配置就完成了。

    三、Glide的使用:

      Glide中的常用方法如下:

     .with() 图片加载的环境:1,Context对象。2,Activity对象。3,FragmentActivity对象。4,Fragment对象
     .load() 加载资源:1,drawable资源。2,本地File文件。3,uri。4,网络图片url。5,byte数组(可以直接加载GIF图片)
     .placeholder() 图片占位符
     .error() 图片加载失败时显示
     .crossFade() 显示图片时执行淡入淡出的动画默认300ms
     .dontAnimate() 不执行显示图片时的动画
     .override() 设置图片的大小
     .centerCrop() 和 fitCenter() 图片的显示方式
     .animate() view动画 2个重构方法
     .transform() bitmap转换
     .bitmapTransform() bitmap转换。比如旋转,放大缩小,高斯模糊等(当用了转换后你就不能使用.centerCrop()或.fitCenter()了。)
     .priority(Priority.HIGH) 当前线程的优先级
     .signature(new StringSignature(“ssss”))
     .thumbnail(0.1f) 缩略图,3个重构方法:优先显示原始图片的百分比(10%)
     .listener() 异常监听
     .into() 图片加载完成后进行的处理:1,ImageView对象。2,宽高值。3,Target对象

      我们用以下两个地址来完成Glide框架的测试,两个地址都是网络图片的URL地址,一个是静态图片的地址,另一个是GIF图片的地址:

        private static final String IMAGE_STATIC_URL = "http://download.pchome.net/wallpaper/pic-2532-1.jpg"; // 静态图片
        private static final String IMAGE_GIF_URL = "http://img1.gamedog.cn/2013/06/22/43-1306220944560.gif"; // GIF图片

    1、Glide的基本用法:

            Glide.with(MainActivity.this) // 在MainActivity中调用Glide的API
                    .load(IMAGE_STATIC_URL) // 加载网络中的静态图片
                    .placeholder(R.mipmap.ic_launcher) // 在图片没有加载出来或加载失败时显示ic_launcher图片
                    .into(iv); // 将图片加载到一个ImageView对象中

      .with()方法中的参数可以有四种类型;.load()方法中的参数可以有五种类型,这里就不多说了,在上面都有,这里重点说一下.into()方法。.into()方法中的参数有三种类型:

      可以是一个ImageView对象,表示图片加载完成之后直接放到ImageView中进行展示,如上面的代码。

      可以是一个宽度值和一个高度值,指定期望得到的图片的宽高值,返回一个GlideDrawable对象。这个方法必须在子线程中进行,具体原因有待研究。贴上代码:

            final Handler glideHanlder = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    if (msg.what == 1) {
                        GlideDrawable glideDrawable = (GlideDrawable) msg.obj;
                        iv.setImageDrawable(glideDrawable);
                    }
                }
            };
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        GlideDrawable glideDrawable = Glide.with(MainActivity.this) // 在MainActivity中调用Glide的API
                                .load(IMAGE_STATIC_URL) // 加载网络中的静态图片
                                .placeholder(R.mipmap.ic_launcher) // 在图片没有加载出来或加载失败时显示ic_launcher图片
                                .into(200, 400) // 设置期望得到的图片的宽高值
                                .get(); // 获取到GlideDrawable对象
                        Message msg = Message.obtain();
                        msg.what = 1;
                        msg.obj = glideDrawable;
                        glideHanlder.sendMessage(msg);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (ExecutionException e) {
                        e.printStackTrace();
                    }
                }
            }).start();

      也可以是一个Target接口、Target接口的子类或实现类,可以有如下图所示的选项:

      使用不同的类或接口作为参数,根据回调的方法进行操作即可。这里贴出使用SimpleTarget的代码:

            Glide.with(MainActivity.this) // 在MainActivity中调用Glide的API
                    .load(IMAGE_STATIC_URL) // 加载网络中的静态图片
                    .into(new SimpleTarget<GlideDrawable>() { // 图片加载回调的Target实现类
                        @Override
                        public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
                            // 图片加载成功时回调的方法
                            iv.setImageDrawable(resource);
                        }
                    });

    2、其他方法解释:

    .asBitmap()和.asGif()

      如果调用了.asBitmap()方法,则.load()中的参数指向的可以是一个静态图片也可以是GIF图片,如果是一张GIF图片,则加载之后只会展示GIF图片的第一帧

      如果调用的.asGif()方法,则.load()方法中的参数指向的必须是一个GIF图片,如果是一张静态图片,则图片加载完成之后展示的只是图片占位符(如果没有设置图片占位符,则什么也不展示)

      这两个方法中只能调用一个,调用了其中一个方法之后,代码提示就不会提示另一个了。代码:

            Glide.with(MainActivity.this) // 在MainActivity中调用Glide的API
                    .load(IMAGE_STATIC_URL) // 加载网络中的静态图片
                    .asBitmap() // 将图片固定成静态图片
                    .placeholder(R.mipmap.ic_launcher) // 图片占位符
                    .into(iv); // 图片加载完成后直接放到ImageView对象iv中进行展示

    .override()

      这个方法可以设置图片加载之后展示的宽度值和高度值,前提是目标ImageView的宽度和高度都设置为wrap_content。代码:

            Glide.with(MainActivity.this) // 在MainActivity中调用Glide的API
                    .load(IMAGE_STATIC_URL) // 加载网络中的静态图片
                    .override(666, 666) // 设置加载之后的图片显示的宽度和高度
                    .placeholder(R.mipmap.ic_launcher) // 图片占位符
                    .into(iv); // 图片加载完成后直接放到ImageView对象iv中进行展示

    .thumbnail()

      设置这个方法之后,可以先加载这张图片的sizeMultiplier倍的缩略图到目标ImageView中,然后再慢慢加载完整的图片。sizeMultiplier值的范围是0~1。代码:

            Glide.with(MainActivity.this) // 在MainActivity中调用Glide的API
                    .load(IMAGE_STATIC_URL) // 加载网络中的静态图片
                    .thumbnail(0.1f) // 先加载一定比例的缩略图
                    .placeholder(R.mipmap.ic_launcher) // 图片占位符
                    .into(iv); // 图片加载完成后直接放到ImageView对象iv中进行展示

    .animate()

      加载图片时展示的动画,可以是Animator类型的属性动画,也可以是int类型的动画资源。这个动画只在第一次加载的时候会展示,以后都会从缓存中获取图片,因此也就不会展示动画了。代码:

            Glide.with(MainActivity.this) // 在MainActivity中调用Glide的API
                    .load(IMAGE_STATIC_URL) // 加载网络中的静态图片
                    .animate(android.R.anim.slide_in_left) // 图片加载完成后的动画效果(从左侧滑入)
                    .into(iv); // 图片加载完成后直接放到ImageView对象iv中进行展示

    .centerCrop()和.fitCenter()

      如果调用了.centerCrop()方法,则显示图片的时候短的一边填充容器,长的一边跟随缩放

      如果调用了.fitCenter()方法,则显示图片的时候长的一边填充容器,短的一边跟随缩放

      这两个方法可以都调用,如果都调用,则最终显示的效果是后调用的方法展示的效果。代码:

            Glide.with(MainActivity.this) // 在MainActivity中调用Glide的API
                    .load(IMAGE_STATIC_URL) // 加载网络中的静态图片
                    .fitCenter() // 长的一边填充容器
                    .centerCrop() // 短的一边填充容器
                    .into(iv); // 图片加载完成后直接放到ImageView对象iv中进行展示

    .bitmapTransform()

      .bitmapTransform()方法中传入的参数是一组Transformation类型的对象,即转换器,可以是任意多个。要想使用Glide为我们提供的转换器,我们需要先在build.gradle文件中导入Glide的Transformations的依赖:

    compile 'jp.wasabeef:glide-transformations:1.0.6'

      这个依赖中为我们提供了很多的转换器,如下:

    圆形:CropCircleTransformation
    方形:CropSquareTransformation
    圆角:RoundedCornersTransformation
    颜色覆盖:ColorFilterTransformation
    置灰:GrayscaleTransformation
    毛玻璃:BlurTransformation

      使用转换器的时候直接new就可以了,但是需要传入一个BitmapPool的对象,我们可以直接传入一个new的LruBitmapPool。例如,我们想得到一个圆形图片的转换器,就可以编写如下代码:

            LruBitmapPool pool = new LruBitmapPool((int) (Runtime.getRuntime().maxMemory()) / 8);
            Glide.with(MainActivity.this) // 在MainActivity中调用Glide的API
                    .load(IMAGE_STATIC_URL) // 加载网络中的静态图片
                    .fitCenter() // 长的一边填充容器
                    .centerCrop() // 短的一边填充容器
                    .bitmapTransform(new CropCircleTransformation(pool)) // 转换器
                    .into(iv); // 图片加载完成后直接放到ImageView对象iv中进行展示

    .resumeRequests()和.pauseRequests()

      这两个方法是为了保证用户界面的滑动流畅而设计的。当在ListView中加载图片的时候,如果用户滑动ListView的时候继续加载图片,就很有可能造成滑动不流畅、卡顿的现象,这是由于Activity需要同时处理滑动事件以及Glide加载图片。Glide为我们提供了这两个方法,让我们可以在ListView等滑动控件滑动的过程中控制Glide停止加载或继续加载,可以有效的保证界面操作的流畅。

      我们需要在ListView的OnScrollListener中写这部分的代码,如下(Adapter中的代码就不贴出来了):

            // ListView滑动时触发的事件
            lv.setOnScrollListener(new AbsListView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(AbsListView view, int scrollState) {
                    switch (scrollState) {
                        case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
                        case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
                            // 当ListView处于滑动状态时,停止加载图片,保证操作界面流畅
                            Glide.with(MainActivity.this).pauseRequests();
                            break;
                        case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
                            // 当ListView处于静止状态时,继续加载图片
                            Glide.with(MainActivity.this).resumeRequests();
                            break;
                    }
                }
    
                @Override
                public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                }
            });

    四、Glide的原理:

      当Glide调用with()方法时,通过传入的Context对象获取一个RequestManager对象。RequestManager类中封装了一个RequestTracker,RequestTracker中有一个List<Request>集合,用来统一管理Request请求。

      当RequestManager对象调用load()方法时,将参数中的值(String或URL或byte[])封装成一种ModelType类型的数据存储到GenericRequestBuilder对象中,并返回一个DrawableRequestBuilder类型的对象(DrawableRequestBuilder是GenericRequestBuilder的子类)。

      当DrawableRequestBuilder对象调用into()方法时,会调用其父类GenericRequestBuilder的obtainRequest()方法,返回一个GenericRequest对象(这个对象是Request接口的一个实现类)。

      GenericRequest对象经过一系列的准备工作之后,调用Engine对象的load()方法开始加载图片。load()方法的加载流程如下:

         * Check the memory cache and provide the cached resource if present
         * Check the current set of actively used resources and return the active resource if present
         * Check the current set of in progress loads and add the cb to the in progress load if present
         * Start a new load

      正如上面的源码注释中介绍的一样,Glide首先去缓存中寻找图片(这个缓存就是一个图片池BitmapPool),如果缓存中有这张图片,则从缓存资源中取出图片进行加载;如果缓存中没有,则从“actively used resources”中找图片,源码中的“actively used resources”指的是一个弱引用组成的Map集合,即如果缓存中没有,就去弱引用中找这张图片,如果弱引用中有这张图片则从弱引用中取出来进行加载;如果弱引用中也没有,则从正在进行的load(Request)中查找有没有哪个Request正在加载这张图片,如果有的话就等待这个Request加载完成之后直接拿过来加载;如果还是没有的话,就只能新开启一个Request从网络中获取了。

      从上面的分析可以看到,Glide加载图片的方式和三级缓存机制很像,Glide中的缓存BitmapPool就像三级缓存中的强引用LruCache,Glide中也有一个弱引用的集合。唯一不同的是,Glide中对正在进行的请求也做了筛选,保证同一张图片只建立一个Request进行加载即可。

      这里顺便科普一下强引用和弱引用之间的工作流程:强引用是一片固定的空间,使用队列的形式存储数据,新来的图片存到队尾,这样可以保证队尾的永远都是最新、最后使用的图片,对头都是最老、最早使用的图片。当强引用中的空间存满的时候,会把对头的图片“踢”出来放到弱引用中。我们之所以要使用弱引用,是因为弱引用可以在内存满了的时候随时GC,因此通常都会用弱引用作为第二级缓存。

            以上就是对Glide的工作流程的总结,有不对之处还望大家不吝赐教,谢谢!

  • 相关阅读:
    linux常用命令
    mysql 开发基础系列20 事务控制和锁定语句(上)
    sql server 性能调优之 资源等待 CXPACKET
    mysql 开发基础系列19 触发器
    mysql 开发基础系列18 存储过程和函数(下)
    mysql 开发基础系列17 存储过程和函数(上)
    sql server 性能调优之 资源等待PAGEIOLATCH
    mysql 开发基础系列16 视图
    mysql 开发基础系列15 索引的设计和使用
    sql server 性能调优之 当前用户请求分析 (1)
  • 原文地址:https://www.cnblogs.com/itgungnir/p/6210882.html
Copyright © 2011-2022 走看看