安卓-Glidel图片加载框架学习笔记

安卓-Glidel图片加载框架学习笔记

引用地址:

muyangmin.github.io/glide-docs-…

以glide Version = ‘4.12.0’为例

1.Gradle配置

此处配置在子模块里(要添加到app主模块也可以),非app主模块里

//glide图片加载框架
implementation "com.github.bumptech.glide:annotations:${rootProject.glideVersion}"
api "com.github.bumptech.glide:glide:${rootProject.glideVersion}"
annotationProcessor "com.github.bumptech.glide:compiler:${rootProject.glideVersion}"
复制代码

app模块只需要添加下面一句,然后app主模块引用上面的子模块

implementation project(":CommonModule")
annotationProcessor "com.github.bumptech.glide:compiler:${rootProject.glideVersion}"
复制代码

2.添加权限声明

添加到子模块AndroidManifest.xml里即可(非app主模块)

<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" />
复制代码

3.如果使用到Proguard

如果你有使用到 proguard,那么请把以下代码添加到你的 proguard.cfg 文件中:

-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}
复制代码

4.@GlideModule 定义AppGlideModule子类和LibraryGlideModule子类

定义一个AppGlideModule子类,定义在app主模块里,而且只能定义在app主模块里。

package com.example.myapp;

import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.AppGlideModule;

@GlideModule
public final class MyAppGlideModule extends AppGlideModule {}
复制代码

定义LibraryGlideModule,定义在非app子模块里。

import android.content.Context;
import android.util.Log;

import androidx.annotation.NonNull;

import com.bumptech.glide.Glide;
import com.bumptech.glide.Registry;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.LibraryGlideModule;

@GlideModule
public class MyLibraryGlideModule extends LibraryGlideModule {
    @Override
    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
        super.registerComponents(context, glide, registry);
        Log.d("MyLibraryGlideModule","MyLibraryGlideModule");
    }
}
复制代码

定义完成后,不要忘记了 Build ->Make Project,然后会生成会在app\build\generated\ap_generated_sources\debug\out的目录下生成相应的文件,如GlideApp.java,LibraryGlideModule也会自动在生成相应的文件。

5.使用 Generated API

Generated API 默认名为 GlideApp ,与 Application 模块中 AppGlideModule的子类包名相同。在 Application 模块中将 Glide.with() 替换为 GlideApp.with(),即可使用该 API 去完成加载工作:

GlideApp.with(fragment)
   .load(myUrl)
   .placeholder(R.drawable.placeholder)
   .fitCenter()
   .into(imageView);
复制代码

占位符:.placeholder(placeholder) 加载中的占位符

加载失败占位符:.error(android.R.drawable.stat_notify_error)

RequestOptions在多个请求之间共享配置

RequestOptions sharedOptions = 
    new RequestOptions()
      .placeholder(placeholder)
      .fitCenter();
      
Glide.with(fragment)
  .load(myUrl)
  .apply(sharedOptions)
  .into(imageView1);

Glide.with(fragment)
  .load(myUrl)
  .apply(sharedOptions)
  .into(imageView2);
复制代码

6.在 ListView 和 RecyclerView 中的使用

在 ListView 或 RecyclerView 中加载图片的代码和在单独的 View 中加载完全一样。Glide 已经自动处理了 View 的复用和请求的取消:

View 调用 clear()into(View),表明在此之前的加载操作会被取消,并且在方法调用完成后,Glide 不会改变 view 的内容。如果你忘记调用 clear(),而又没有开启新的加载操作,那么就会出现这种情况,你已经为一个 view 设置好了一个 Drawable,但该 view 在之前的位置上使用 Glide 进行过加载图片的操作,Glide 加载完毕后可能会将这个 view 改回成原来的内容。

这里的代码以 RecyclerView 的使用为例,但规则同样适用于 ListView。

正确用法1

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    String url = urls.get(position);
    Glide.with(fragment)
        .load(url)
        .into(holder.imageView);
}
复制代码

正确用法2

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    if (isImagePosition(position)) {
        String url = urls.get(position);
        Glide.with(fragment)
            .load(url)
            .into(holder.imageView);
    } else {
        Glide.with(fragment).clear(holder.imageView);
        holder.imageView.setImageDrawable(specialDrawable);
    }
}
复制代码

7.非 View 目标

除了将 BitmapDrawable 加载到 View 之外,你也可以开始异步加载到你的自定义 Target 中:

Glide.with(context
  .load(url)
  .into(new CustomTarget<Drawable>() {
    @Override
    public void onResourceReady(Drawable resource, Transition<Drawable> transition) {
      // Do something with the Drawable here.
    }

    @Override
    public void onLoadCleared(@Nullable Drawable placeholder) {
      // Remove the Drawable provided in onResourceReady from any Views and ensure 
      // no references to it remain.
    }
  });
复制代码

8.后台线程

后台线程下载,

FutureTarget<Bitmap> futureTarget =
  Glide.with(context)
    .asBitmap()
    .load(url)
    .submit(width, height);

Bitmap bitmap = futureTarget.get();

// Do something with the Bitmap and then when you're done with it:
Glide.with(context).clear(futureTarget);
复制代码

后台同步实现图片下载

 //不能直接在主线程里调用,会直接ANR
FutureTarget<File> futureTarget = Glide.with(GlideImageLoadFragment.this)
 .asFile()
 .load("https://dss3.bdstatic.com/iPoZeXSm1A5BphGlnYG/skin/822.jpg?2")
 .addListener(new RequestListener<File>() {
      @Override
      public boolean onLoadFailed(@Nullable GlideException e,
                                  Object model, Target<File> target,
                                   boolean isFirstResource) {
       return false;
     }

     @Override
     public boolean onResourceReady(File resource, Object model, Target<File> target, DataSource dataSource, boolean isFirstResource) {
         return false;
      }
  }).submit();
  
//下载到的文件没有扩展名。
 File file = futureTarget.get();
复制代码

异常下载图片并回调 .asFile()

GlideApp.with(this)
        .asFile()
        .load("https://img.soogif.com/rSlMSm7msQagXhSSgIQ0LtqTusCK712l.gif")
        .into(new CustomTarget<File>() {
            @Override
            public void onResourceReady(@NonNull File resource, @Nullable Transition<? super File> transition) {
                Log.d("", "");
            }

            @Override
            public void onLoadCleared(@Nullable Drawable placeholder) {
                Log.d("", "");
            }
        });
复制代码

8.Glide扩展 GlideExtension

@GlideExtension 注解用于标识一个扩展 Glide API 的类。任何扩展 Glide API 的类都必须使用这个注解来标记,否则其中被注解的方法就会被忽略。

@GlideExtension 注解的类应以工具类的思维编写。这种类应该有一个私有的、空的构造方法,应为 final 类型,并且仅包含静态方法。被注解的类可以含有静态变量,可以引用其他的类或对象。

在 Application 模块中可以根据需求实现任意多个被 @GlideExtension 注解的类,在 Library 模块中同样如此。当 AppGlideModule 被发现时,所有有效的 Glide 扩展类 会被合并,所有的选项在 API 中均可以被调用。合并冲突会导致 Glide 的 Annotation Processor 抛出编译错误。

@GlideExtention 注解的类有两种扩展方式:

  1. GlideOption – 为 RequestOptions 添加一个自定义的选项。
  2. GlideType – 添加对新的资源类型的支持(GIF,SVG 等等)。

@GlideExtension

@GlideExtension只能在app模块里使用。

//@GlideExtension 注解到类上面,只能在app模块里使用。
@GlideExtension
public class MyAppExtension {
  // Size of mini thumb in pixels.
  private static final int MINI_THUMB_SIZE = 100;

  private MyAppExtension() { } // utility class

//@GlideOption注解到方法里面。标记的方法应该为静态方法
  @NonNull
  @GlideOption
  public static BaseRequestOptions<?> miniThumb(BaseRequestOptions<?> options) {
    return options
      .fitCenter()
      .override(MINI_THUMB_SIZE);
  }
  
 // 你可以为方法任意添加参数,但要保证第一个参数为 RequestOptions。 标记的方法应该为静态方法
  	@GlideOption
	public static BaseRequestOptions<?> miniThumb(BaseRequestOptions<?> options, int size) {
  		return options
    		.fitCenter()
    		.override(size);
	}
}
复制代码

添加完成后 执行 Build ->Make Project,可以看到app\build\generated\ap_generated_sources\debug\out\my\android\architecture\samples\glide\GlideOptions.java

里生成了下面的方法

@SuppressWarnings("unchecked")
@CheckResult
@NonNull
public GlideOptions miniThumb() {
  return (GlideOptions) MyAppExtension.miniThumb(this);
}

/**
 * @see MyAppExtension#miniThumb(BaseRequestOptions, int)
 */
@SuppressWarnings("unchecked")
@CheckResult
@NonNull
public GlideOptions miniThumb(int size) {
  return (GlideOptions) MyAppExtension.miniThumb(this, size);
}
复制代码

调用

GlideApp.with(fragment)
   .load(url)
   .miniThumb(thumbnailSize)
   .into(imageView);
复制代码

GlideType

@GlideType 注解的静态方法用于扩展 RequestManager 。被 @GlideType 注解的方法允许你添加对新的资源类型的支持,包括指定默认选项。

例如,为添加对 GIF 的支持,你可以添加一个被 @GlideType 注解的方法:

@GlideExtension
public class MyAppExtension {
  private static final RequestOptions DECODE_TYPE_GIF = decodeTypeOf(GifDrawable.class).lock();

  @NonNull
  @GlideType(GifDrawable.class)
  public static RequestBuilder<GifDrwable> asGif(RequestBuilder<GifDrawable> requestBuilder) {
    return requestBuilder
      .transition(new DrawableTransitionOptions())
      .apply(DECODE_TYPE_GIF);
  }
}
复制代码

这样会生成一个包含对应方法的 RequestManager

public class GlideRequests extends RequesetManager {

  public GlideRequest<GifDrawable> asGif() {
    return (GlideRequest<GifDrawable> MyAppExtension.asGif(this.as(GifDrawable.class));
  }
  
  ...
}
复制代码

9.占位符

Glide允许用户指定三种不同类型的占位符,分别在三种不同场景使用:

placeholder
error
fallback

占位符(Placeholder)

占位符是当请求正在执行时被展示的 Drawable 。当请求成功完成时,占位符会被请求到的资源替换。如果被请求的资源是从内存中加载出来的,那么占位符可能根本不会被显示。如果请求失败并且没有设置 error Drawable ,则占位符将被持续展示。类似地,如果请求的url/model为 null ,并且 error Drawablefallback 都没有设置,那么占位符也会继续显示。

错误符(Error)

error Drawable 在请求永久性失败时展示。error Drawable 同样也在请求的url/model为 null ,且并没有设置 fallback Drawable 时展示。

后备回调符(Fallback)

fallback Drawable 在请求的url/model为 null 时展示。设计 fallback Drawable 的主要目的是允许用户指示 null 是否为可接受的正常情况。例如,一个 null 的个人资料 url 可能暗示这个用户没有设置头像,因此应该使用默认头像。然而,null 也可能表明这个元数据根本就是不合法的,或者取不到。 默认情况下Glide将 null 作为错误处理,所以可以接受 null 的应用应当显式地设置一个 fallback Drawable

占位符是异步加载的吗?

No。占位符是在主线程从Android Resources加载的。我们通常希望占位符比较小且容易被系统资源缓存机制缓存起来。

变换是否会被应用到占位符上?

No。Transformation仅被应用于被请求的资源,而不会对任何占位符使用。

在应用中包含必须在运行时做变换才能使用的图片资源是很不划算的。相反,在应用中包含一个确切符合尺寸和形状要求的资源版本几乎总是一个更好的办法。假如你正在加载圆形图片,你可能希望在你的应用中包含圆形的占位符。另外你也可以考虑自定义一个View来剪裁(clip)你的占位符,而达到你想要的变换效果。

在多个不同的View上使用相同的Drawable可行么?

通常可以,但不是绝对的。任何无状态(non-stateful)的 Drawable(例如 BitmapDrawable )通常都是ok的。但是有状态的 Drawable 不一样,在同一时间多个 View 上展示它们通常不是很安全,因为多个View会立刻修改(mutate) Drawable 。对于有状态的 Drawable ,建议传入一个资源ID,或者使用 newDrawable() 来给每个请求传入一个新的拷贝。

10.选项

1.请求选项

Glide中的大部分设置项都可以直接应用在 Glide.with() 返回的 RequestBuilder 对象上。

可用的选项包括(但不限于):

  • 占位符(Placeholders)
  • 转换(Transformations)
  • 缓存策略(Caching Strategies)
  • 组件特有的设置项,例如编码质量,或Bitmap的解码配置等。

例如,要应用一个 CenterCrop 转换,你可以使用以下代码:

Glide.with(fragment)
    .load(url)
    .centerCrop()
    .into(imageView);
复制代码

RequestOptions对象 apply(@NonNull BaseRequestOptions<?> options)

如果你想让你的应用的不同部分之间共享相同的加载选项,你也可以初始化一个新的 RequestOptions 对象,并在每次加载时通过 apply() 方法传入这个对象:

RequestOptions cropOptions = new RequestOptions().centerCrop(context);
...
Glide.with(fragment)
    .load(url)
    .apply(cropOptions)
    .into(imageView);
复制代码

apply() 方法可以被调用多次,因此 RequestOption 可以被组合使用。如果 RequestOptions 对象之间存在相互冲突的设置,那么只有最后一个被应用的 RequestOptions 会生效。

过渡选项 transition

不同于RequestOptionsTransitionOptions是特定资源类型独有的,你能使用的变换取决于你让Glide加载哪种类型的资源。

这样的结果是,假如你请求加载一个 Bitmap ,你需要使用 BitmapTransitionOptions ,而不是 DrawableTransitionOptions 。同样,当你请求加载 Bitmap时,你只需要做简单的淡入,而不需要做复杂的交叉淡入。

RequestBuilder

使用 RequestBuilder 可以指定:

  • 你想加载的资源类型(Bitmap, Drawable, 或其他)
  • 你要加载的资源地址(url/model)
  • 你想最终加载到的View
  • 任何你想应用的(一个或多个)RequestOption 对象
  • 任何你想应用的(一个或多个)TransitionOption 对象
  • 任何你想加载的缩略图 thumbnail()

选择资源类型

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享