Before you know it, we have reached the sixth part of our series of Glide tutorials, half a year after the first basic use of Glide was released. In this half a year, we through usage explanation and source code analysis with the way of learning, will Glide all aspects of the research over, I believe that can always see here friends are now a Glide master.
The Glide series, which is expected to have a total of eight articles, is coming to an end. But the further we go, the deeper we dig. So today, let’s take a look at one of the deeper, but very important, features of Glide: custom modules.
Basic usage of custom modules
Glide is a very, very simple thing to use, and most of the time, the image loading effect that we want to achieve is a line of code. But Glide’s simplistic API also raises the question of what to do if we want to change some of Glide’s default configuration items. It’s hard to imagine changing a Glide configuration item into a line of classic Glide picture load statements. Yes, this is where the custom module function comes in.
The custom module function can change The Glide configuration, replace the Glide components and other operations independently, so that we can easily customize the various configurations of Glide, and Glide picture loading logic without any intersection, which is also a low coupling programming way. So let’s look at the basic usage of custom modules.
First we need to define our own module class and have it implement the GlideModule interface, as follows:
public class MyGlideModule implements GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
}
@Override
public void registerComponents(Context context, Glide glide) {
}
}
Copy the code
As you can see, in the MyGlideModule class, we overwrote the applyOptions() and registerComponents() methods, which are used to change Glide and configure and replace Glide components, respectively. We will be able to change the Glide configuration or replace the Glide components by adding specific logic to the two methods later.
However, our custom MyGlideModule is not yet recognized by Glide. If you want it to work, you have to add the following configuration to the Androidmanifest.xml file:
<manifest>
...
<application>
<meta-data
android:
android:value="GlideModule" />
...
</application>
</manifest>
Copy the code
Add a meta-data configuration item to the tag where Android :name is specified as the full path to our custom MyGlideModule and Android :value must be specified as GlideModule, which is a fixed value.
So, we have finished the function of Glide custom module, isn’t it very simple? Glide is now able to recognize our custom MyGlideModule, but before writing the specific functions, let’s read the source code as usual and analyze how it recognizes the custom MyGlideModule from the source level.
The principle of custom modules
Instead of parsing the source code line by line through the first steps of Glide code execution, I will only analyze the parts related to custom modules. If you want to read the source Glide again, you can go to see the second article in this series of Android picture loading framework most complete analysis (two), from the perspective of the source understand Glide’s execution process.
Obviously we are used to a neat line of Glide. With (context).load(URL).into(imageView), but we never seem to have noticed an instance of Glide itself. In fact, Glide does have an instance created, but it is automatically created and managed internally by Glide, so developers don’t have to worry about it most of the time, just call its static methods.
So where exactly is an instance of Glide created? Glide: Get (); get(); get();
public class Glide { private static volatile Glide glide; . public static Glide get(Context context) { if (glide == null) { synchronized (Glide.class) { if (glide == null) { Context applicationContext = context.getApplicationContext(); List<GlideModule> modules = new ManifestParser(applicationContext).parse(); GlideBuilder builder = new GlideBuilder(applicationContext); for (GlideModule module : modules) { module.applyOptions(applicationContext, builder); } glide = builder.createGlide(); for (GlideModule module : modules) { module.registerComponents(applicationContext, glide); } } } } return glide; }... }Copy the code
Let’s take a closer look at the code above. First, a singleton pattern is used to get an instance of Glide object, and as you can see, this is a very typical double-lock pattern. Then, on line 12, we call ManifestParser’s parse() method to parse the configuration in the Androidmanifest.xml file, This essentially reads all the meta-data configuration from the AndroidManifest with GlideModule values and instantiates the corresponding custom module. Since you can customize as many modules as you want, here we get a List collection of the GlideModule.
Next, in line 13, we create a GlideBuilder object and call each of the GlideModule’s applyOptions() methods through a loop, passing the GlideBuilder object into the method as a parameter. The applyOptions() method is where we can add our own logic, although we haven’t written any yet.
The next critical step is to call the createGlide() method of GlideBuilder and return a Glide object. That is, an instance of Glide object is created here, so let’s go to this method and have a look:
public class GlideBuilder { private final Context context; private Engine engine; private BitmapPool bitmapPool; private MemoryCache memoryCache; private ExecutorService sourceService; private ExecutorService diskCacheService; private DecodeFormat decodeFormat; private DiskCache.Factory diskCacheFactory; . 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); }}Copy the code
This method creates instances of BitmapPool, MemoryCache, DiskCache, DecodeFormat, and so on, and creates an instance of Glide in the last line, and passes those instances into the Glide object. For subsequent image loading operations.
But have you noticed that the createGlide() method does a null check on any object that is created, and only creates an instance of the object if it is empty? That is, if we can initialize and assign these objects in advance in the applyOptions() method, then we don’t have to recreate their instances in the createGlide() method, thus enabling the ability to change Glide configuration. And we’re going to demonstrate that in a minute.
Now we go back to Glide’s get() method, get an instance of the Glide object, and then call each GlideModule’s registerComponents() method through a loop. Here we can add the logic to replace the components of Glide.
Ok, that’s how the Glide custom module works. Now that we know how it works, all the questions focus on how to add the actual logic to the applyOptions() and registerComponents() methods, which we’ll look at in a minute.
Change Glide Configuration
If you want to change the default configuration of Glide, you only need to initialize the configuration item for Glide in advance in the applyOptions() method. So what configuration items does Glide come with? Here I give you an example:
-
SetMemoryCache () is used to configure Glide’s memory cache policy. The default configuration is LruResourceCache.
-
SetBitmapPool () is used to configure Glide’s Bitmap cache pool. The default configuration is LruBitmapPool.
-
SetDiskCache () is used to configure the Glide hard disk caching strategies, the default configuration is InternalCacheDiskCacheFactory.
-
SetDiskCacheService () is used to configure picture asynchronous execution of Glide read from the cache, the default configuration is FifoPriorityThreadPoolExecutor, namely “first-in first-out” principle.
-
SetResizeService () is used to configure Glide read picture asynchronous execution of the cache, the default configuration is also FifoPriorityThreadPoolExecutor.
-
SetDecodeFormat () is used to set the decoding mode for Glide loading pictures. The default configuration is RGB_565.
These default configurations of Glide are very scientific and sound, and the caching algorithms used are very efficient, so we don’t need to change them in most cases, which is one of the reasons Glide’s usage is so simple.
But the default configuration of Glide Science does not prevent us from learning to customize the function of Glide module, so there will always be situations where the default configuration will not be enough for you, and it is up to us to change the default configuration ourselves.
Let’s take a look at it through specific examples. Just said to Glide the default disk cache strategy use is InternalCacheDiskCacheFactory, the cache will all Glide loaded pictures are stored to the current application of private directory. This is a very secure approach, but it also causes some inconvenience, as the private directory is not viewable even by the developer itself, which is a bit tricky if I want to verify that the image has been successfully cached.
In this case, it is a good idea to use custom modules to change the default configuration of Glide. We can fully to realize DiskCache. Factory interface from the definition of a hard disk caching strategies, but it is not necessary to do so greatly, because Glide itself with built-in a ExternalCacheDiskCacheFactory, Can allow loaded images to be cached to the SD card.
Then, we will try to use this to replace the default ExternalCacheDiskCacheFactory InternalCacheDiskCacheFactory, thus will Glide loading pictures of all the cache to the SD card.
Since we created a custom module MyGlideModule earlier, we can now write the logic directly here, as follows:
public class MyGlideModule implements GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
builder.setDiskCache(new ExternalCacheDiskCacheFactory(context));
}
@Override
public void registerComponents(Context context, Glide glide) {
}
}
Copy the code
Yes, it’s that simple. Now all Glide loaded images are cached on the SD card.
In addition, InternalCacheDiskCacheFactory and ExternalCacheDiskCacheFactory default disk cache size is 250 MB. That is, if your app has more than 250 MB of cached images, Glide will use the DiskLruCache algorithm to clean the cached images.
Of course, the default cache size can be changed, and it can be changed very simply as follows:
public class MyGlideModule implements GlideModule {
public static final int DISK_CACHE_SIZE = 500 * 1024 * 1024;
@Override
public void applyOptions(Context context, GlideBuilder builder) {
builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, DISK_CACHE_SIZE));
}
@Override
public void registerComponents(Context context, Glide glide) {
}
}
Copy the code
Only need to ExternalCacheDiskCacheFactory or InternalCacheDiskCacheFactory pass in a parameter is ok, now we will adjust the Glide hard disk the size of the cache is 500 m.
Well, it is so simple to change the function of Glide configuration, so next we will verify that the change of configuration is effective.
Here, we use the basic Glide loading statement to load a web image:
String url = "http://guolin.tech/book.png";
Glide.with(this)
.load(url)
.into(imageView);
Copy the code
Run the program, the effect is as follows:
OK, now that the image is loaded, let’s go find its cache.
ExternalCacheDiskCacheFactory default cache path is in sdcard/Android/package/cache/image_manager_disk_cache directory, we use the file browser into this directory, the result is shown in the following figure.
As you can see, there are two files, of which the journal file is the log file for the DiskLruCache algorithm. This file is essential and there will only be one. If you want to learn more about DiskLruCache, you can go to my blog to read my full resolution of Android DiskLruCache, the best solution for hard disk caching.
The other file is the cached image. The file name may look strange, but we just need to change the suffix of the file to.png and open it in the image browser. The result is clear, as shown below.
This proves that we have successfully changed Glide’s hard disk cache path to the SD card.
Another point here is that we all know Glide and Picasso are very similar, but there is one big difference. Glide’s default loading format is RGB_565, Picasso’s default loading format is ARGB_8888. ARGB_8888 is a more nuanced format, but has a higher memory overhead. RGB_565 format images are more memory saving, but the image effect will be worse.
Glide and Picasso’s default image formats are not superior or inferior, only their own trade-offs. But if you want Glide to use the ARGB_8888 image format as well, that’s fine. All we need to do is change the default configuration in MyGlideModule, as follows:
public class MyGlideModule implements GlideModule {
public static final int DISK_CACHE_SIZE = 500 * 1024 * 1024;
@Override
public void applyOptions(Context context, GlideBuilder builder) {
builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, DISK_CACHE_SIZE));
builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
}
@Override
public void registerComponents(Context context, Glide glide) {
}
}
Copy the code
With this configuration, all images loaded using Glide will be in ARGB_8888 format. The image quality will be better, but the memory overhead will be significantly higher, so be prepared.
Ok, so much for changing the Glide configuration, let’s move on to the next very important topic, replacing the Glide component.
Replace Glide component
Replacing Glide component functionality requires specific replacement logic in the custom module’s registerComponents() method. Replacing this function with a Glide component is significantly more difficult than changing the Glide configuration. Glide components are very diverse and complex, but in most cases we don’t really need to replace them. One component, however, has a larger replacement requirement: Glide’s HTTP communications component.
Glide by default uses a custom HTTP communication component based on native HttpURLConnection, but most Android developers today prefer to use OkHttp, So the need to change the HTTP communication component from Glide to OkHttp is a common one, so today we will use this capability as an example.
Let’s take a look at what components are currently available in Glide. In the Construction method of Glide class, it looks like this:
public class 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()); . }}Copy the code
As you can see, a component is registered by calling the register() method, and the parameters passed in the register() method indicate what type of parameter Glide supports to load images, and how to handle this type of image loading. Here’s an example:
register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
Copy the code
Glide. With (context).load(new GlideUrl(“url…”) ) into (imageView) way to load the image, and HttpUrlGlideUrlLoader. The Factory is responsible for dealing with specific network communication logic. If we wanted to replace Glide’s HTTP communication component with OkHttp, we would simply register a component of type GlideUrl in the custom module.
GlideUrl: GlideUrl: GlideUrl: GlideUrl: GlideUrl: GlideUrl: GlideUrl: GlideUrl: GlideUrl Why re-register a GlideUrl component instead of a String component? The truth is simple, because the Load (String) method is Glide Glide, and its base layer is still the GlideUrl component that we call, so we just need to replace the bottom layer when we replace the component, and we’re done.
So let’s start learning exactly how to replace Glide’s HTTP communication component with OkHttp.
The first step, needless to say, is to introduce the OkHttp library into the current project, as follows:
Dependencies {the compile 'com. Squareup. Okhttp3: okhttp: 3.9.0'}Copy the code
And then what do we do? All we have to do is follow suit. Just said Glide network communication logic is by HttpUrlGlideUrlLoader. The Factory to be responsible for you, then we will take a look at its source code:
public class HttpUrlGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> {
private final ModelCache<GlideUrl, GlideUrl> modelCache;
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() {
}
}
public HttpUrlGlideUrlLoader() {
this(null);
}
public HttpUrlGlideUrlLoader(ModelCache<GlideUrl, GlideUrl> modelCache) {
this.modelCache = modelCache;
}
@Override
public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) {
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);
}
}
Copy the code
As you can see, HttpUrlGlideUrlLoader. The Factory is an inner class, the outer HttpUrlGlideUrlLoader class implements the ModelLoader < GlideUrl, InputStream > this interface, Rewrite the getResourceFetcher() method. In the getResourceFetcher() method, an instance of HttpUrlFetcher is created, and this is where the actual network communication logic is handled:
public class HttpUrlFetcher implements DataFetcher<InputStream> { private static final String TAG = "HttpUrlFetcher"; private static final int MAXIMUM_REDIRECTS = 5; private static final HttpUrlConnectionFactory DEFAULT_CONNECTION_FACTORY = new DefaultHttpUrlConnectionFactory(); private final GlideUrl glideUrl; private final HttpUrlConnectionFactory connectionFactory; private HttpURLConnection urlConnection; private InputStream stream; private volatile boolean isCancelled; public HttpUrlFetcher(GlideUrl glideUrl) { this(glideUrl, DEFAULT_CONNECTION_FACTORY); } HttpUrlFetcher(GlideUrl glideUrl, HttpUrlConnectionFactory connectionFactory) { this.glideUrl = glideUrl; this.connectionFactory = connectionFactory; } @Override public InputStream loadData(Priority priority) throws Exception { return loadDataWithRedirects(glideUrl.toURL(), 0 , null , glideUrl.getHeaders()); } private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers) throws IOException { if (redirects >= MAXIMUM_REDIRECTS) { throw new IOException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!" ); } else { try { if (lastUrl ! = null && url.toURI().equals(lastUrl.toURI())) { throw new IOException("In re-direct loop"); } } catch (URISyntaxException e) { } } urlConnection = connectionFactory.build(url); for (Map.Entry<String, String> headerEntry : headers.entrySet()) { urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue()); } urlConnection.setConnectTimeout(2500); urlConnection.setReadTimeout(2500); urlConnection.setUseCaches(false); urlConnection.connect(); if (isCancelled) { return null; } final int statusCode = urlConnection.getResponseCode(); if (statusCode / 100 == 2) { return getStreamForSuccessfulRequest(urlConnection); } else if (statusCode / 100 == 3) { String redirectUrlString = urlConnection.getHeaderField("Location"); if (TextUtils.isEmpty(redirectUrlString)) { throw new IOException("Received empty or null redirect url"); } URL redirectUrl = new URL(url, redirectUrlString); return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers); } else { if (statusCode == -1) { throw new IOException("Unable to retrieve response code from HttpUrlConnection."); } throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage()); } } private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection) throws IOException { if (TextUtils.isEmpty(urlConnection.getContentEncoding())) { int contentLength = urlConnection.getContentLength(); stream = ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength); } else { stream = urlConnection.getInputStream(); } return stream; } @Override public void cleanup() { if (stream ! = null) { try { stream.close(); } catch (IOException e) { } } if (urlConnection ! = null) { urlConnection.disconnect(); } } @Override public String getId() { return glideUrl.getCacheKey(); } @Override public void cancel() { isCancelled = true; } interface HttpUrlConnectionFactory { HttpURLConnection build(URL url) throws IOException; } private static class DefaultHttpUrlConnectionFactory implements HttpUrlConnectionFactory { @Override public HttpURLConnection build(URL url) throws IOException { return (HttpURLConnection) url.openConnection(); }}}Copy the code
Does this code look effortless? It’s just HttpURLConnection usage. Just copy the HttpUrlFetcher code and replace the HTTP communication component with OkHttp.
Now create a new OkHttpFetcher class that also implements the DataFetcher interface as follows:
public class OkHttpFetcher implements DataFetcher<InputStream> { private final OkHttpClient client; private final GlideUrl url; private InputStream stream; private ResponseBody responseBody; private volatile boolean isCancelled; public OkHttpFetcher(OkHttpClient client, GlideUrl url) { this.client = client; this.url = url; } @Override public InputStream loadData(Priority priority) throws Exception { Request.Builder requestBuilder = new Request.Builder() .url(url.toStringUrl()); 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 (IOException e) { e.printStackTrace(); } } @Override public String getId() { return url.getCacheKey(); } @Override public void cancel() { isCancelled = true; }}Copy the code
The above code is exactly what I wrote from HttpUrlFetcher, using some of the basic OkHttp usage, so I don’t need to explain anything more. As you can see, writing code for network communication using OkHttp is much simpler and has fewer lines of code than using HttpURLConnection. Note that on line 22 I added an Httplib: OkHttp header, which we’ll use for testing later. You don’t need to add this header to your actual project code.
OkHttpGlideUrlLoader OkHttpGlideUrlLoader OkHttpGlideUrlLoader OkHttpGlideUrlLoader Create a new OkHttpGlideUrlLoader class and implement the ModelLoader<GlideUrl, InputStream> interface as follows:
public class OkHttpGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> { private 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() { } } public OkHttpGlideUrlLoader(OkHttpClient client) { this.okHttpClient = client; } @Override public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) { return new OkHttpFetcher(okHttpClient, model); }}Copy the code
Note that I provide two constructors for Factory, one that takes no arguments and one that takes OkHttpClient arguments. If you don’t need any custom configuration for OkHttp, just call the Factory constructor with no arguments, which automatically creates an OkHttpClient instance internally. But if you need to add interceptors, or change OkHttp’s default timeout configuration, create an instance of OkHttpClient and pass it into the Factory constructor.
Now, the last step is to register the OkHttpGlideUrlLoader and OkHttpFetcher to Glide, and replace the original HTTP communication component, as shown below:
public class MyGlideModule implements GlideModule { ... @Override public void registerComponents(Context context, Glide glide) { glide.register(GlideUrl.class, InputStream.class, new OkHttpGlideUrlLoader.Factory()); }}Copy the code
As you can see, Glide’s register() method is also called here to register the component. The Map type used in the register() method is used to store registered components, so we re – register a component of type glideurl.class, replacing the original component.
Theoretically, now that we have successfully replaced Glide’s HTTP communication component with OkHttp, the only question is how do we verify that the replacement is successful?
I have thought of many ways to verify, such as adding an OkHttp interceptor, or set up a test server. But to give you the most direct view of the result, I’m going to use Fiddler to capture the package. The usage of this tool is very simple, but I will not introduce the use of this tool in this article due to the lack of space, and the friends who have not used this tool can understand it through this article.
Before we can start the verification, we need to modify the Glide loading code again, as shown below:
String url = "http://guolin.tech/book.png";
Glide.with(this)
.load(url)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(imageView);
Copy the code
I have disabled both memory and hard disk caching for Glide; otherwise, Glide might read the image it just cached and not restart the end request.
Ok, now let’s reload the picture using Glide, and observe the packet capture in Fiddler, as shown in the picture below.
As you can see, in the HTTP request header we did add httplib: OkHttp ourselves. That is to say, Glide’s HTTP communication component has been successfully replaced.
Simpler component replacement
The above method is that we replaced the HTTP communication component of Glide by hand. If you don’t want to go to so much trouble, you can also, Glide official provides us with a very simple way to replace the HTTP component. It also supports OkHttp2 and Volley in addition to OkHttp3.
We just need to add a few lines of library configuration to Gradle. For example, the configuration of using OkHttp3 as an HTTP communication component is as follows:
Dependencies {the compile 'com. Squareup. Okhttp3: okhttp: 3.9.0' compile 'com. Making. Bumptech. Glide: okhttp3 - integration: 1.5.0 @ aar'}Copy the code
The configuration of using OkHttp2 as an HTTP communication component is as follows:
Dependencies {the compile 'com. Making. Bumptech. Glide: okhttp - integration: 1.5.0 @ aar' compile 'com. Squareup. Okhttp: okhttp: 2.7.5'}Copy the code
The configuration of using Volley as the HTTP communication component is as follows:
Dependencies {the compile 'com. Making. Bumptech. Glide: volley - integration: 1.5.0 @ aar' compile 'com. McXiaoke. Volley: library: 1.0.19'}Copy the code
Of course, the philosophy behind these libraries is exactly the same as the one we just implemented manually replacing HTTP components ourselves. Learning how to manually replace components makes it easier to extend richer functionality, so it’s important to master this skill.
Well, that’s all for today’s article. In the next article, we will use the knowledge learned in this article, Glide to carry on a advanced function extension, interested friends please continue to read Android picture loading framework most complete analysis (seven), Glide picture loading function with progress.
Pay attention to my technical public account “Guo Lin”, there are high-quality technical articles pushed every day. Pay attention to my entertainment public number, work, study tired when relax yourself.
Scan the qr code below on wechat to follow: