Glide学习笔记之自定义模块

基本用法:

public class MyGlideModule implements GlideModule {
			
			@Override
			public void applyOptions(Context context, GlideBUilder builder) {
			
			}
			
			@Override
			public void registerComponents(Context context, Glide glide) {
			}
			
		}
以上这两个需要我们重写的方法就是来更改Glide配置以及替换Glide组件的,注意:

目前Glide还不能识别我们自定义的MyGlideModule,还需要在AndroidManifest.xml中做一下配置

<manifest>
			
				...
				
				<application>
				
					<meta-data>
						这个name是指我们自定义的MyGlideModule的完整路径
						android:name="com.example.glidetest.MyGlideModule"
						这个value必须指定为GlideMoudle,这样glide在builde的时候才能识别到
						android:value="GlideModule" />
						
					...
				</application>
			</manifest>
源码分析:

先来看Glide的构建glide对象:

public static Glide get(Context context) {
			if (glide == null) {
			// 通过单例模式来获取glide对象
				synchronized (Glide.class) {
					if (glide == null) {
						Context applicationContext = context.getApplicationContext();
						// 通过ManifestParser.parse()来解析AndiordManifest.xml中的文件配置
						List<GlideModule> modules = new ManifestParser(applicationContext).parse();

						GlideBuilder builder = new GlideBuilder(applicationContext);
						for (GlideModule module : modules) {
						// 循环的调用每一个GlideModule的中的applyOptions(),这里也就是我们自定义逻辑的地方
							module.applyOptions(applicationContext, builder);
						}
						// 构建glide
						glide = builder.createGlide();
						for (GlideModule module : modules) {
						// 在获取到glide对象后,通过循环调用每个GlideModule的redisterComponents()来实现glide的逻辑替换
							module.registerComponents(applicationContext, glide);
						}
					}
				}
			}

			return glide;
		}

说明了为什要将value指定为GlideModule

private static final String GLIDE_MODULE_VALUE = "GlideModule";

public List<GlideModule> parse() {
		
			List<GlideModule> modules = new ArrayList<GlideModule>();
			try {
				ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
						context.getPackageName(), PackageManager.GET_META_DATA);
				if (appInfo.metaData != null) {
				// 通过循环来获取所有的值为GlideModule的配置,返回一个GlideModule的集合
					for (String key : appInfo.metaData.keySet()) {
						if (GLIDE_MODULE_VALUE.equals(appInfo.metaData.get(key))) {
							modules.add(parseModule(key));
						}
					}
				}
			} catch (PackageManager.NameNotFoundException e) {
				throw new RuntimeException("Unable to find metadata to parse GlideModules", e);
			}

			return modules;
		}
		

构建glide:

Glide createGlide() {
			if (sourceService == null) {
				final int cores = Math.max(1, Runtime.getRuntime().availableProcessors());
				sourceService = new FifoPriorityThreadPoolExecutor(cores);
			}
			if (diskCacheService == null) {
				diskCacheService = new FifoPriorityThreadPoolExecutor(1);
			}

			MemorySizeCalculator calculator = new MemorySizeCalculator(context);
			if (bitmapPool == null) {
				if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
					int size = calculator.getBitmapPoolSize();
					bitmapPool = new LruBitmapPool(size);
				} else {
					bitmapPool = new BitmapPoolAdapter();
				}
			}

			if (memoryCache == null) {
				memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
			}

			if (diskCacheFactory == null) {
				diskCacheFactory = new InternalCacheDiskCacheFactory(context);
			}

			if (engine == null) {
				engine = new Engine(memoryCache, diskCacheFactory, diskCacheService, sourceService);
			}

			if (decodeFormat == null) {
				decodeFormat = DecodeFormat.DEFAULT;
			}

			return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);
		}

会创建BitmapPool、MemoryCache、DiskCache、DecodeDroamt、Engine等对象的实例,并在最后返回的Glide对象中将创建的实例传入进去,以供后续的图片加载操作使用。在创建对象的时候首先回去判断是否为null只有为null的才会创建,所以我们可以自己在applyOptions()中提前初始化并赋值,在createGlide的时候就不会去创建了,从而就实现的glide的配置的更改功能

更改Glide的配置:
只需在applyOptions()中提前将Glide的配置项进行初始化
1、setMemoryCache()
用于设置Glide的内存缓存策略,默认为LruResourceCache
2、setBitmapPool()
配置Glide的Bitmap缓存池,默认为LruBitmapPool
3、setDisCache()
配置Glide的硬盘缓存策略,默认为InternalCacheDiskCacheFactory
4、setDiskCacheService()
配置Glide读取缓存中图片的异步执行器,默认配置是FifoPriorityThreadPoolExecutor,也就是先入先出原则
5、setResizeService()
配置Glide读取非缓存中的图片的异步执行器,默认也是FifoPriorityThreadPoolExecutor
6、setDecodeFormat()
配置Glide加载图片的解码模式,默认为PREFER_RGB_565

不过以上的配置我们几乎都不需要去更改

替换Glide组件:

查看Glide中的组件:

Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {
        
		...

        register(File.class, ParcelFileDescriptor.class, new FileDescriptorFileLoader.Factory());
        register(File.class, InputStream.class, new StreamFileLoader.Factory());
        register(int.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
        register(int.class, InputStream.class, new StreamResourceLoader.Factory());
        register(Integer.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
        register(Integer.class, InputStream.class, new StreamResourceLoader.Factory());
        register(String.class, ParcelFileDescriptor.class, new FileDescriptorStringLoader.Factory());
        register(String.class, InputStream.class, new StreamStringLoader.Factory());
        register(Uri.class, ParcelFileDescriptor.class, new FileDescriptorUriLoader.Factory());
        register(Uri.class, InputStream.class, new StreamUriLoader.Factory());
        register(URL.class, InputStream.class, new StreamUrlLoader.Factory());
        register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
        register(byte[].class, InputStream.class, new StreamByteArrayLoader.Factory());

       ...
		
    }
例如:我们将Glide的网络请求改成OKHttp的register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());直接将这里面的http通讯组件改成okhttp的

查看HttpUrlGlideUrlLoader的源码:

public class HttpUrlGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> {

		private final ModelCache<GlideUrl, GlideUrl> modelCache;

		/**
		 * The default factory for {@link com.bumptech.glide.load.model.stream.HttpUrlGlideUrlLoader}s.
		 */
		public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
			private final ModelCache<GlideUrl, GlideUrl> modelCache = new ModelCache<GlideUrl, GlideUrl>(500);

			@Override
			public ModelLoader<GlideUrl, InputStream> build(Context context, GenericLoaderFactory factories) {
				return new HttpUrlGlideUrlLoader(modelCache);
			}

			@Override
			public void teardown() {
				// Do nothing.
			}
		}

		public HttpUrlGlideUrlLoader() {
			this(null);
		}

		public HttpUrlGlideUrlLoader(ModelCache<GlideUrl, GlideUrl> modelCache) {
			this.modelCache = modelCache;
		}

		
		@Override
		public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) {
			// GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time spent parsing urls.
			GlideUrl url = model;
			if (modelCache != null) {
				url = modelCache.get(model, 0, 0);
				if (url == null) {
					modelCache.put(model, 0, 0, model);
					url = model;
				}
			}
			// 主要的网络请求在这里
			return new HttpUrlFetcher(url);
		}
	}
通过查看HttpUrlFetcher源码可以知道:其实就是HttpURLConnection

所以我们替换成okhttp来处理:

1、模仿Glide的HttpUrlFetcher写出自己的OkHttpFetcher

public class OkHttpFetcher implements DataFetcher<InputStream> {

		private GlideUrl url;
		private OkHttpClient client;
		private InputStream stream;
		private ResponseBody responseBody;
		private volatile boolean isCancelled;

		public OkHttpFetcher(GlideUrl url, OkHttpClient client) {
			this.url = url;
			this.client = client;
		}

		@Override
		public InputStream loadData(Priority priority) throws Exception {
			Request.Builder requestBuilder = new Request.Builder();
			requestBuilder.url(url.toString());

			for (Map.Entry<String, String> headerEntry :url.getHeaders().entrySet()) {
				String key = headerEntry.getKey();
				requestBuilder.addHeader(key, headerEntry.getValue());
			}
			//这个请求头是测试用,实际项目中可以不用添加
			requestBuilder.addHeader("httplib", "OkHttp");
			Request request = requestBuilder.build();
			if (isCancelled) {
				return null;
			}
			Response response = client.newCall(request).execute();
			responseBody = response.body();
			if (!response.isSuccessful() || responseBody == null) {
				throw new IOException("Request failed with code: " + response.code());
			}

			stream = ContentLengthInputStream.obtain(responseBody.byteStream(), responseBody.contentLength());

			return stream;
		}

		@Override
		public void cleanup() {
			try {
				if (stream != null) {
					stream.close();
				}
				if (responseBody != null) {
					responseBody.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		@Override
		public String getId() {
			return url.getCacheKey();
		}

		@Override
		public void cancel() {
			isCancelled = true;
		}
	}

2、模仿Glide的HttpUrlGlideUrlLoader来写出自己的OkHttpGlideUrlLoader

public class OkHttpGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> {

		private OkHttpClient okHttpClient;
		public OkHttpGlideUrlLoader(OkHttpClient okHttpClient) {
			this.okHttpClient = okHttpClient;
		}

		public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {


			private OkHttpClient client;

			public Factory() {
			}

			public Factory(OkHttpClient client) {
				this.client = client;
			}

			private synchronized OkHttpClient getOkHttpClient() {
				if (client == null) {
					client = new OkHttpClient();
				}
				return client;
			}

			@Override
			public ModelLoader<GlideUrl, InputStream> build(Context context, GenericLoaderFactory factories) {
				return new OkHttpGlideUrlLoader(getOkHttpClient());
			}

			@Override
			public void teardown() {

			}
		}
		@Override
		public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) {
			return new OkHttpFetcher(model, okHttpClient);
		}
	}

3、将上面创建的OkHttpUrlFetcher和OkHttpGlideUrlLoader注册到Glide中(注意:需要在AndroidManifest中配置)

public class MyGlideModule implements GlideModule {
		@Override
		public void applyOptions(Context context, GlideBuilder builder) {

		}

		@Override
		public void registerComponents(Context context, Glide glide) {
			glide.register(GlideUrl.class, InputStream.class, new OkHttpGlideUrlLoader.Factory());
		}
	}
以上都是我们自己手写的,Glide有官方的替换方法(其背后的原理也就是我们上面所分析的)

利用okhttp3来作为http的通讯:

dependencies {
		compile 'com.squareup.okhttp3:okhttp:3.9.0'
		compile 'com.github.bumptech.glide:okhttp3-integration:1.5.0@aar'
	}
利用volley来作为http通讯:
dependencies {
		compile 'com.github.bumptech.glide:volley-integration:1.5.0@aar'  
		compile 'com.mcxiaoke.volley:library:1.0.19'
	}

猜你喜欢

转载自blog.csdn.net/qq_36447701/article/details/80526337