Glide配置和自定义组件流程
先看下GlideModule接口1
2
3
4public interface GlideModule {
    void applyOptions(Context context, GlideBuilder builder);
    void registerComponents(Context context, Glide glide);
}
实现GlideModule接口
1  | public class CustomGlideMoudle implements GlideModule{  | 
在AndroidManifest.xml中进行配置
1  | <meta-data  | 
Glide配置项解析
Glide的配置即在applyOptions()中的GlideBuilder一共有下面这些项可以配置。1
2
3
4
public void applyOptions(Context context, GlideBuilder builder) {
   builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
}
- setDecodeFormat(DecodeFormat.PREFER_ARGB_8888):将Glide的解码格式设置为ARGB_8888的,默认是RGB_565。
 - setBitmapPool(new BitmapPool(){}):BitmapPool是bitmap缓存池的实现的接口,自定义配置的话,实现这个接口里边的方法就可以了。BitmapPool的默认实现是在sdk api11之前是空实现,在api11之后是LruBitmapPool这个类实现的,有对自定义实现bitmap缓存池感兴趣的可以用LruBitmapPool作为参考研究。
 - setDiskCache(new DiskCache.Factory(){}):设置磁盘缓存,默认的磁盘路径和大小是image_manager_disk_cache 和 250M,可以重新实现这个接口,修改目录和大小。
 - setDiskCacheService(ExecutorService):设置磁盘缓存线程执行器,这个方法可以使用app中共用的线程执行器,每个开源组件都有自己的线程池和执行器,避免app的线程过多问题。
 - setMemoryCache(new MemoryCache(){}):Glide内存缓存资源的缓存实现,可以按照这个接口自己实现,默认实现是使用的LruCache。
 - setResizeService(ExecutorService):设置图片从原始图片的尺寸转换到要放到ImageView中的尺寸大小的线程执行器,也可以使用系统共用的线程执行器。
Glide自定义组件流程分析
1
2
3
4
public void registerComponents(Context context, Glide glide) {
} 

先看下这个register()方法
1  | public <T, Y> void register(Class<T> modelClass, Class<Y> resourceClass, ModelLoaderFactory<T, Y> factory) {  | 
- 第一个参数modleClass是请求参数类型
 - 第二个参数resourceClass是将请求参数转换的类型
 - 第三个参数factory就是将第一个参数转换成第二个参数的方法的类型。
 
ModelLoader使用流程
GenericLoaderFactory.buildModelLoader(modelClass, resourceClass)
这个方法返回值是ModelLoader。1
2
3public interface ModelLoader<T, Y> {
    DataFetcher<Y> getResourceFetcher(T model, int width, int height);
}
调用ModelLoader的getResourceFetcher()方法会返回DataFetcher的对象
DataFetcher中的loadData()方法就是执行转换数据的过程。这种以factory存储类型转换处理的方式可以在自己的app开发中学习使用。
Glide中一共有13个register()方法,只有下面这两个是直接实现的,其他的都是在这两个基础上调用这两个实现的。1
2register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
register(byte[].class, InputStream.class, new StreamByteArrayLoader.Factory());
例如:1
register(File.class, ParcelFileDescriptor.class, new FileDescriptorFileLoader.Factory());
就是调用的factories.buildModelLoader(Uri.class, ParcelFileDescriptor.class)。最终的就是上面那两个实现的。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class FileDescriptorFileLoader extends FileLoader<ParcelFileDescriptor>
        implements FileDescriptorModelLoader<File> {
    public static class Factory implements ModelLoaderFactory<File, ParcelFileDescriptor> {
        
        public ModelLoader<File, ParcelFileDescriptor> build(Context context, GenericLoaderFactory factories) {
            return new FileDescriptorFileLoader(factories.buildModelLoader(Uri.class, ParcelFileDescriptor.class));
        }
        
        public void teardown() {
            // Do nothing.
        }
    }
    public FileDescriptorFileLoader(Context context) {
        this(Glide.buildFileDescriptorModelLoader(Uri.class, context));
    }
    public FileDescriptorFileLoader(ModelLoader<Uri, ParcelFileDescriptor> uriLoader) {
        super(uriLoader);
    }
}
介绍一下直接实现的register(byte[].class, InputStream.class, new StreamByteArrayLoader.Factory());1
2
3
4
5
6
7
8
9
10
11
12
13public class StreamByteArrayLoader implements StreamModelLoader<byte[]> {
    ... ...
public DataFetcher<InputStream> getResourceFetcher(byte[] model, int width, int height) {
    return new ByteArrayFetcher(model, id);
}
public static class Factory implements ModelLoaderFactory<byte[], InputStream> {
    
    public ModelLoader<byte[], InputStream> build(Context context, GenericLoaderFactory factories) {
        return new StreamByteArrayLoader();
    }
    ... ...
}
这个类最终调用的new ByteArrayFetcher(model, id);1
2
3
4
5
6
7
8public class ByteArrayFetcher implements DataFetcher<InputStream> {
     ... ...
    
    public InputStream loadData(Priority priority) {
        return new ByteArrayInputStream(bytes);
    }
     ... ...
}
其实就是将字节数组转换成了输入流的方法。
还有另外一个直接实现的方法:1
register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
下面是转换类的源码HttpUrlGlideUrlLoader.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class HttpUrlGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> {
    ... ...
    public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
    ... ...
        
        public ModelLoader<GlideUrl, InputStream> build(Context context, GenericLoaderFactory factories) {
            return new HttpUrlGlideUrlLoader(modelCache);
        }
    }
    ... ...
    
    public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) {
    ... ...
        return new HttpUrlFetcher(url);
    }
}
下面是HttpUrlFetcher的实现源码,内容就是用HttpURLConnection作网络请求的一个过程。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
     Map<String, String> headers) throws IOException {
   if (redirects >= MAXIMUM_REDIRECTS) {
     throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
   } else {
     // Comparing the URLs using .equals performs additional network I/O and is generally broken.
     // See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
     try {
       if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
         throw new HttpException("In re-direct loop");
       }
     } catch (URISyntaxException e) {
       // Do nothing, this is best effort.
     }
   }
   urlConnection = connectionFactory.build(url);
   for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
     urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
   }
   urlConnection.setConnectTimeout(timeout);
   urlConnection.setReadTimeout(timeout);
   urlConnection.setUseCaches(false);
   urlConnection.setDoInput(true);
   // Stop the urlConnection instance of HttpUrlConnection from following redirects so that
   // redirects will be handled by recursive calls to this method, loadDataWithRedirects.
   urlConnection.setInstanceFollowRedirects(false);
   // Connect explicitly to avoid errors in decoders if connection fails.
   urlConnection.connect();
   // Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352.
   stream = urlConnection.getInputStream();
   if (isCancelled) {
     return null;
   }
   final int statusCode = urlConnection.getResponseCode();
   if (isHttpOk(statusCode)) {
     return getStreamForSuccessfulRequest(urlConnection);
   } else if (isHttpRedirect(statusCode)) {
     String redirectUrlString = urlConnection.getHeaderField("Location");
     if (TextUtils.isEmpty(redirectUrlString)) {
       throw new HttpException("Received empty or null redirect url");
     }
     URL redirectUrl = new URL(url, redirectUrlString);
     // Closing the stream specifically is required to avoid leaking ResponseBodys in addition
     // to disconnecting the url connection below. See #2352.
     cleanup();
     return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
   } else if (statusCode == INVALID_STATUS_CODE) {
     throw new HttpException(statusCode);
   } else {
     throw new HttpException(urlConnection.getResponseMessage(), statusCode);
   }
 }
 private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection)
     throws IOException {
   if (TextUtils.isEmpty(urlConnection.getContentEncoding())) {
     int contentLength = urlConnection.getContentLength();
     stream = ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength);
   } else {
     if (Log.isLoggable(TAG, Log.DEBUG)) {
       Log.d(TAG, "Got non empty content encoding: " + urlConnection.getContentEncoding());
     }
     stream = urlConnection.getInputStream();
   }
   return stream;
 }
Glide配置项和自定义组件的加载机制
要想知道Glide配置项和自定义组件是如何加载的,还是要从Glide.with(this).load(url).into(imageView);流程说起。
最开始是Glide.with()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75  public static Glide get(@NonNull Context context) {
    if (glide == null) {
      synchronized (Glide.class) {
        if (glide == null) {
          checkAndInitializeGlide(context);
        }
      }
    }
    return glide;
  }
  private static void checkAndInitializeGlide(@NonNull Context context) {
    if (isInitializing) {
      throw new IllegalStateException("You cannot call Glide.get() in registerComponents(),"
          + " use the provided Glide instance instead");
    }
    isInitializing = true;
    initializeGlide(context);
    isInitializing = false;
  }
  private static void initializeGlide(@NonNull Context context) {
    initializeGlide(context, new GlideBuilder());
  }
  private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
    Context applicationContext = context.getApplicationContext();
    GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
    List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
    if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
      manifestModules = new ManifestParser(applicationContext).parse();
    }
    if (annotationGeneratedModule != null
        && !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
      Set<Class<?>> excludedModuleClasses =
          annotationGeneratedModule.getExcludedModuleClasses();
      Iterator<com.bumptech.glide.module.GlideModule> iterator = manifestModules.iterator();
      while (iterator.hasNext()) {
        com.bumptech.glide.module.GlideModule current = iterator.next();
        if (!excludedModuleClasses.contains(current.getClass())) {
          continue;
        }
        if (Log.isLoggable(TAG, Log.DEBUG)) {
          Log.d(TAG, "AppGlideModule excludes manifest GlideModule: " + current);
        }
        iterator.remove();
      }
    }
    if (Log.isLoggable(TAG, Log.DEBUG)) {
      for (com.bumptech.glide.module.GlideModule glideModule : manifestModules) {
        Log.d(TAG, "Discovered GlideModule from manifest: " + glideModule.getClass());
      }
    }
    RequestManagerRetriever.RequestManagerFactory factory =
        annotationGeneratedModule != null
            ? annotationGeneratedModule.getRequestManagerFactory() : null;
    builder.setRequestManagerFactory(factory);
    for (com.bumptech.glide.module.GlideModule module : manifestModules) {
      module.applyOptions(applicationContext, builder);
    }
    if (annotationGeneratedModule != null) {
      annotationGeneratedModule.applyOptions(applicationContext, builder);
    }
    Glide glide = builder.build(applicationContext);
    for (com.bumptech.glide.module.GlideModule module : manifestModules) {
      module.registerComponents(applicationContext, glide, glide.registry);
    }
    if (annotationGeneratedModule != null) {
      annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
    }
    applicationContext.registerComponentCallbacks(glide);
    Glide.glide = glide;
}
- 从AndroidManifest.xml中读取配置信息
 - 执行GlideModule.applyOptions()方法的内容
 - 执行GlideModule.registerComponents()方法。
 
Glide已有的开源组件
Glide的http组件已有很多开源的,使用的时候只要配置一下就可以了
使用OkHttp3来作为HTTP通讯组件的配置如下:1
2
3
4dependencies {
    compile 'com.squareup.okhttp3:okhttp:3.9.0'
    compile 'com.github.bumptech.glide:okhttp3-integration:1.5.0@aar'
}
使用Volley来作为HTTP通讯组件的配置如下:1
2
3
4dependencies {
    compile 'com.github.bumptech.glide:volley-integration:1.5.0@aar' 
    compile 'com.mcxiaoke.volley:library:1.0.19' 
}