preface

  • Glide, the function is very powerful Android picture loading open source framework I believe we are not unfamiliar

  • Because of its powerful function, its source code is very complex, which causes many people to be discouraged

  • I try to decompose the function of Glide, and separate for each function of the source code analysis, so as to reduce the complexity of Glide source code.

Next, I will launch a series of Glide function source analysis, interested can continue to pay attention to

  • Today, I will mainly for Glide picture caching function of flow & source code analysis, I hope you will like it.

As the article is long, I hope readers will first collect & reserve enough time to view.


directory


1. Glide Cache mechanism introduction

1.1 Cached image resources

Image resources that Glide needs to cache fall into two categories:

  • Original picture (Source) : the initial size & resolution of the source image
  • Converted image (Result) : a picture that has been scaled and compressed

When using Glide to load an image, Glide defaults to compressing and converting the image based on the View and does not display the original image (this is why Glide loads faster than Picasso)

1.2 Cache mechanism design

  • GlideThe cache function is designed asThe second level cache: Memory cache & hard disk cache

It’s not a level 3 cache, because loading from the network is not a cache

  • Cache read order: memory cache -> disk cache -> network
  1. Memory caching is enabled by default
  2. GlideIn, memory cache and disk cache do not affect each other and are configured independently
  • Level 2 cache has different functions:
    1. Memory cache: Prevents applications from repeatedly reading image data into memory

    Only converted images are cached

    1. Hard disk cache: Prevents applications from repeatedly downloading and reading data from the network or other places

    Can cache the original picture & cache the converted picture, set by the user

Glide’s cache mechanism allows Glide to have a very good picture cache effect, resulting in a high picture loading efficiency.

For example, slide up and down in RecyclerView, and RecyclerView as long as it is Glide loaded pictures, can be read directly from the memory & display, so as not to repeat from the network or hard disk read, improve the efficiency of picture loading.

2. Glide Cache function

  • GlideCaches are divided into memory caches and disk caches
  • The details are as follows

2.1 Memory Cache

  • Function: Prevents applications from reading image data into memory repeatedly

Cache only converted images, not the original images

  • By default,GlideAutomatically enable memory caching
Glide. With (this).load(url).into(imageView); Glide. Glide. With (this).load(url).skipMemoryCache(true) // Disable memory caching. Into (imageView);Copy the code
  • Realize the principle ofGlideThe memory cache implementation is based on:LruCacheAlgorithm (Least Recently Used) & weak reference mechanism
  1. LruCacheAlgorithm principle: will most recently used objectsUse strong referencesStored in theLinkedHashMap; When the cache is full,Removes the least recently used object from memory
  2. Weak references: Weakly referenced objects have shorter lifecycles because they are notJVMWhen garbage collection is performed, weak reference objects are collected whenever they are found (whether there is sufficient memory or not)

2.2 Disk Caching

  • Function: Prevents applications from repeatedly downloading and reading data from the network or other places

Can cache the original picture & cache the converted picture, set by the user

  • The specific use
Glide.with(this) .load(url) .diskCacheStrategy(DiskCacheStrategy.NONE) .into(imageView); Diskcachestrategy. NONE: No image is cached, that is, disk caching is disabled. // diskCacheStrategy. ALL: // diskCacheStrategy. SOURCE: Cache only raw images (original full-resolution images, i.e., not converted images) // diskCacheStrategy. RESULT: (Default) only cached converted images (final images: reduced resolution/converted images, no original images cachedCopy the code
  • Implementation PrincipleGlideThe custom ofDiskLruCachealgorithm
  1. The algorithm is based onLruIn the algorithm,DiskLruCacheAlgorithm, which is used in disk caching scenarios
  2. The algorithm is encapsulated toGlideCustom utility class (the utility class is based onAndroidTo provide theDiskLruCacheUtility class

3. Parse the Glide cache process

  • GlideThe entire caching process starts fromLoading image requestAt the beginning, the process includes read & write of the memory cache and read & write of the disk cache, which is the focus of this article
  • Specific as follows

Next, I’ll analyze the source code for each step in the Glide cache process.


4. Source code analysis of cache process

Step 1: Generate a cache Key

  • GlideThe implementation of memory & disk caching is based onImage cache KeyUniquely identify

That is, according to the image cache Key to the cache to find the corresponding cache image

  • To generate cacheKeyThe code takes place inEngineOf the classload()In the

# This code was analyzed in the previous article, but the cache-related content was ignored. Now only the cache-related code is posted

public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedListener, EngineResource.ResourceListener { public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher, DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder, Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) { Util.assertMainThread(); long startTime = LogTime.getLogTime(); final String id = fetcher.getId(); // Get an id string, which is the unique identifier of the image to load. EngineKey = keyFactory.buildKey(ID, signature, Width, height, loadProvider.getCacheDecoder(),loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),transcoder, loadProvider.getSourceEncoder()); // Create a EngineKey object by passing the id and signature, width, height, etc. into the factory method of the cache Key. By overriding equals() andhashCode(), which ensures that the EngineKey object is the same only if all the parameters of the EngineKey are the same. }Copy the code

At this point, Glide’s picture cache Key is generated.


Step 2: Create a cache objectLruResourceCache

  • The LruResourceCache object is created when the Glide object is created

  • Glide object is created when loadGeneric() creates the ModelLoader object in step 2 load()

  • See source code analysis

<-- loadGeneric() --> private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {... ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context); // Create the first ModelLoader object; Function: Glide passes different types of parameters to the Load () method to get different ModelLoader objects. So get the StreamStringLoader object (realized ModelLoader interface) / / Glide. BuildStreamModelLoader () analysis - > < 1 > analysis - analysis of 1: Glide. BuildStreamModelLoader () - > public class Glide {public static < T, Y > ModelLoader < T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass, Context context) {if (modelClass == null) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "Unable to load null model, setting placeholder only");
            }
            return null;
        }
        returnGlide.get(context).getLoaderFactory().buildModelLoader(modelClass, resourceClass); <-- parse 2: Glide. Get () --> // Function: Create a Glide object in singleton mode public static Glide GET (Context Context) {// Implement singleton functionif (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(); // Create Glide object in Builder mode ->> Analysis 3for(GlideModule module : modules) { module.registerComponents(applicationContext, glide); }}}}returnglide; CreateGlide () --> public class GlideBuilder {... GlidecreateGlide() {
        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()); // create a LruResourceCache object and assign it to the memoryCache object // this LruResourceCache object = Glide implement memoryCache LruCache object}returnnew Glide(engine, memoryCache, bitmapPool, context, decodeFormat); }}Copy the code

At this point, the cache object LruResourceCache is created

Step 3: Fetch the cached image from the memory cache

  • GlideThe cached image is fetched from the memory cache before the image is loaded
  • Read the memory cache code inEngineOf the classload()In the

This is where the cache Key is generated, as explained above

  • Source code analysis
public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedListener, EngineResource.ResourceListener { ... public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher, DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder, Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) { Util.assertMainThread(); final String id = fetcher.getId(); EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(), loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(), transcoder, loadProvider.getSourceEncoder()); Key EngineResource<? > cached = loadFromCache(key, isMemoryCacheable); // Call loadFromCache() to get the cached image in the memory cacheif(cached ! = null) { cb.onResourceReady(cached); } // Call cb.onresourceready () to EngineResource<? > active = loadFromActiveResources(key, isMemoryCacheable);if(active ! = null) { cb.onResourceReady(active); } // If not, call loadFromActiveResources(); // If not, call loadFromActiveResources(); // If not, start a new thread. EngineJob current = jobs.get(key);return new LoadStatus(cb, current);
        }

        EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
        DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
                transcoder, diskCacheProvider, diskCacheStrategy, priority);
        EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
        jobs.put(key, engineJob);
        engineJob.addCallback(cb);
        engineJob.start(runnable);

        returnnew LoadStatus(cb, engineJob); }... }Copy the code

That is:

  • GlideSplit the memory cache into two pieces: one is usedLruCacheAlgorithm mechanism; The other uses a weak reference mechanism
  • When the memory cache is fetched, two methods are used to fetch the cache from the above two regions
  1. loadFromCache(): From useLruCacheThe algorithm mechanism’s memory cache retrieves the cache
  2. loadFromActiveResources(): Retrieves the cache from an in-memory cache that uses a weak-reference mechanism

Source code analysis is as follows:

/ / this two methods belong to the Engine class public class Engine implements EngineJobListener, MemoryCache. ResourceRemovedListener, EngineResource.ResourceListener { private final MemoryCache cache; private final Map<Key, WeakReference<EngineResource<? >>> activeResources; . <-- method 1: loadFromCache() --> > loadFromCache(Key key, boolean isMemoryCacheable) {if(! isMemoryCacheable) {returnnull; / / if isMemoryCacheable =falseSkipMemoryCache () - skipMemoryCache() - skipMemoryCache()true), where isMemoryCacheable is equal tofalse} EngineResource<? > cached = getEngineResourceFromCache(key); // Get the image cache ->> Analysis 4if(cached ! = null) { cached.acquire(); activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue())); // activeResources = a weakly referenced HashMap: used to cache images in use // Benefits: Protects images from being recycled by LruCache. ->> Method 2}returncached; } < < - analysis 4: getEngineResourceFromCache () - > > / / action: get photo cache / / specific process: according to the cache Key value from the cache / / note: The cache object is the LruResourceCache object created when the Glide object is built. Private EngineResource<? > getEngineResourceFromCache(Key key) { Resource<? > cached = cache.remove(key); // When the cached image is retrieved from LruResourceCache, it is removed from the cache ->> Return to method 1 final EngineResource result;if (cached == null) {
            result = null;
        } else if (cached instanceof EngineResource) {
            result = (EngineResource) cached;
        } else {
            result = new EngineResource(cached, true /*isCacheable*/);
        }
        returnresult; } <-- method 2: loadFromActiveResources() --> // activeResources = a weakly referenced HashMap: used to cache images in use private EngineResource<? > loadFromActiveResources(Key key, boolean isMemoryCacheable) {if(! isMemoryCacheable) {returnnull; } EngineResource<? > active = null; WeakReference<EngineResource<? >> activeRef = activeResources.get(key);if(activeRef ! = null) { active = activeRef.get();if(active ! = null) { active.acquire(); }else{ activeResources.remove(key); }}returnactive; }... }Copy the code

If the above two methods do not get the image cache (that is, there is no image cache in the memory cache), start a new thread to load the image.


  • At this point, the steps to obtain the memory cache are explained.
  • conclusion


Step 4: Start the image loading thread

  • Glide starts the image loading thread if it cannot get the cached image from the memory cache

  • But Glide does not load the image immediately after the thread is started. Instead, Glide uses Glide’s second level of cache, the disk cache, to retrieve the cached image

  • Start with decode () in the image thread run () in step 3.

private Resource<? > decode() throws Exception {// When executing the image loading thread, there are two cases: // Case 1: // Case 2: No picture is read from the disk cache // Case 1: Picture is read from the disk cacheif(isDecodingFromCache()) {// Depending on whether it is enabled when using the API, if diskCacheStrategy.None is used, no images are cached, that is, disk caching is disabledreturndecodeFromCache(); ->> Go directly to step 4 analysis 9}else{// Case 2: Not reading images from disk cache // As discussed above, reading images from network is not described here too muchreturndecodeFromSource(); }}Copy the code

Step 5: Get the cache image from the disk cache

Glide uses the second level of cache: disk cache to retrieve the cached image if it cannot get the cached image from the memory cache

<-- 解 释 9: decodeFromCache() --> private Resource<? > decodeFromCache() throws Exception { Resource<? > result = null; result = decodeJob.decodeResultFromCache(); // This is the mode set when using disk cache. DecodeResultFromCache () ->> 解 决 10}if(result == null) { result = decodeJob.decodeSourceFromCache(); // If you can't get the converted image cache, get the original image cache. DecodeSourceFromCache () ->> decodeSourceFromCachereturnresult; } <-- decodeFromCache() --> public Resource<Z> decodeResultFromCache() throws Exception {decodeResultFromCache() throws Exception {if(! diskCacheStrategy.cacheResult()) {returnnull; } Resource<T> transformed = loadFromCache(resultKey); <Z> result = transcode(transformed);returnresult; } <-- analysis 11: <-- analysis 11: <-- analysis 11: decodeFromCache() --> private Resource<T> loadFromCache(Key key) throws IOException { File cacheFile = diskCacheProvider.getDiskCache().get(key); // 1. Call getDiskCache() to get the DiskLruCache utility class instance written by Glide Glide. Call get() of the above instance and pass in the full cache Key, resulting in the disk cached fileif (cacheFile == null) {
        returnnull; } Resource<T> result = null; try { result = loadProvider.getCacheDecoder().decode(cacheFile, width, height); } finally {if(result == null) { diskCacheProvider.getDiskCache().delete(key); }}returnresult; // If the file is not empty, decode it as a Resource object and return to analysis 10} <-- analysis 12: decodeFromCache() --> public Resource<Z> decodeSourceFromCache() throws Exception {if(! diskCacheStrategy.cacheSource()) {returnnull; } Resource<T> decoded = loadFromCache(resultKey.getOriginalKey()); // the OriginalKey uses only id and signature. // the OriginalKey uses only id and signature. // the OriginalKey uses only id and signature. So the Original cache Key is basically determined by the ID (i.e. the image URL). // loadFromCache () is the same as analysis 11, but the cache Key passed in is differentreturntransformEncodeAndTranscode(decoded); // 2. Convert the image data and then decode it.Copy the code
  • At this point, the hard disk cache read the end of the source analysis.
  • conclusion


Step 6: Obtain image resources from the network

  • inGlideIf the image cache is not available in either of the two levels of caching mechanisms, you have to go to the source (such as the network) to load the image
  • Before loading an image from the network, obtain the network resources of the image
  1. Ignore process #2 for now. If you are interested, see # Process in the article

Step 7: Write to disk cache

  • Glide Time to write the picture to the disk cache: after obtaining the picture resource, before the picture is loaded

  • Write to disk cache is divided into: write the original picture or converted picture to disk cache

  • From the previous article:Android: this is a comprehensive & detailed picture loading library Glide source analysisIn step 3Into ()To execute the picture threadThe run ()In theDecode ()Start (analysis 13 above) and repost the code here
private Resource<? > decode() throws Exception {// When executing the image loading thread, there are two cases: // Case 1: // Case 2: No picture is read from the disk cache // Case 1: Picture is read from the disk cacheif (isDecodingFromCache()) {
        returndecodeFromCache(); // The entry to the disk cache is here, as explained above.else{// Case 2: do not read images from disk cache // that is, read images from network, do not use cache // Write disk cache is written here ->> Analysis 13returndecodeFromSource(); }} <-- analysis 13: decodeFromSource() --> public Resource<Z> decodeFromSource() throws Exception { Resource<T> decoded = decodeSource(); // Parse images // Entry to write raw images to disk cache ->> Analysis 14 // Look back from analysis 16 herereturntransformEncodeAndTranscode(decoded); // Write to disk cache entry after conversion ->> analysis 17} <-- analysis 14: decodeSource() --> private Resource<T> decodeSource() throws Exception { Resource<T> decoded = null; try { final A data = fetcher.loadData(priority); // Read the image dataif (isCancelled) {
            returnnull; } decoded = decodeFromSourceData(data); 15} finally {fetcher.cleanup(); }returndecoded; } <-- analysis 15: decodeFromSourceData() --> private Resource<T> decodeFromSourceData(A data) throws IOException { final Resource<T> decoded; Diskcachestrategy. ALL or diskCacheStrategy. SOURCE is used when using the disk caching APIif(diskCacheStrategy.cacheSource()) { decoded = cacheAndDecodeSourceData(data); // Call cacheAndDecodeSourceData() to cache raw images if allowed ->> Parse 16}else {
        long startTime = LogTime.getLogTime();
        decoded = loadProvider.getSourceDecoder().decode(data, width, height);
    }
    returndecoded; } <-- analysis 16: cacheAndDecodeSourceData --> private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {... diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer); // 1. Call getDiskCache() to get DiskLruCache instance // 2. // getOriginalKey() = getOriginalKey(); TransformEncodeAndTranscode () - > private Resource < Z > transformEncodeAndTranscode (Resource < T > decoded) {Resource < T > transformed = transform(decoded); WriteTransformedToCache (transformed); // writeTransformedToCache(transformed); 18 Resource<Z> result = transcode(transformed);returnresult; } <-- 解 决 18: TransformedToCache() --> private void writeTransformedToCache(Resource<T> transformed) {if(transformed == null || ! diskCacheStrategy.cacheResult()) {return; } diskCacheProvider.getDiskCache().put(resultKey, writer); // 1. Call getDiskCache() to get DiskLruCache instance // 2. Call put() to write to disk cache // Note: The cached Key of the transformed image is a complete resultKey, that is, contains more than 10 parameters}Copy the code
  • At this point, the hard disk cache write analysis is complete.
  • conclusion


Step 9: Write to memory cache

  • Glide time to write the picture to memory cache: after the picture is loaded, before the picture is displayed

  • In the previous article, when the image is loaded, a message is sent to the EngineJob Handler to cut the execution logic back to the main thread, thus executing handleResultOnMainThread()

class EngineJob implements EngineRunnable.EngineRunnableManager { private final EngineResourceFactory engineResourceFactory; . private voidhandleResultOnMainThread() {... / / concern 1: write a weak reference cache engineResource = engineResourceFactory. Build (resource, isCacheable); listener.onEngineJobComplete(key, engineResource); // Concern 2: Write the LruCache algorithm cache engineResource. Acquire ();for (ResourceCallback cb : cbs) {
            if(! isInIgnoredCallbacks(cb)) { engineResource.acquire(); cb.onResourceReady(engineResource); } } engineResource.release(); }Copy the code

Write memory cache is divided into: write weak reference cache & LruCache algorithm cache

  1. The memory cache is divided into: a block usedLruCacheArea of algorithmic mechanism & a cache that uses weak reference mechanism
  2. The memory cache only caches the converted image

Concern 1: Write to the weak reference cache

class EngineJob implements EngineRunnable.EngineRunnableManager { private final EngineResourceFactory engineResourceFactory; . private voidhandleResultOnMainThread() {... / / write a weak reference cache engineResource = engineResourceFactory. Build (resource, isCacheable); / / create a contains picture resources resource EngineResource listener object. The onEngineJobComplete (key, EngineResource); / / the above create EngineResource object into the Engine. The onEngineJobComplete () - > > analysis 6 / / write cache LruCache algorithm (ignore) EngineResource. Acquire ();for (ResourceCallback cb : cbs) {
            if(! isInIgnoredCallbacks(cb)) { engineResource.acquire(); cb.onResourceReady(engineResource); } } engineResource.release(); } <<- Analysis 6: OnEngineJobComplete () () - > > public class Engine implements EngineJobListener, MemoryCache. ResourceRemovedListener, EngineResource.ResourceListener { ... @Override public void onEngineJobComplete(Key key, EngineResource<? > resource) { Util.assertMainThread();if(resource ! = null) { resource.setResourceListener(key, this);if(resource.isCacheable()) { activeResources.put(key, new ResourceWeakReference(key, resource, getReferenceQueue())); // Add the EngineResource object passed in to activeResources () // that is, write the weak reference memory cache}} jobs.remove(key); }... }Copy the code

Concern 2: Write to the LruCache algorithm cache

class EngineJob implements EngineRunnable.EngineRunnableManager { private final EngineResourceFactory engineResourceFactory; . private voidhandleResultOnMainThread() {... / / write a weak reference cache (ignore) engineResource = engineResourceFactory. Build (resource, isCacheable); listener.onEngineJobComplete(key, engineResource); // Write the LruCache algorithm cache engineResource. Acquire (); / / mark 1for (ResourceCallback cb : cbs) {
            if(! isInIgnoredCallbacks(cb)) { engineResource.acquire(); // tag 2 cb.onResourceReady(engineResource); } } engineResource.release(); // mark 3}Copy the code

A reference mechanism for the EngineResource object containing the image resource resource:

  • With aacquiredVariable records the number of times an image is referenced
  • When loading images: callacquire()Add 1 to the variable

Above code tag 1, tag 2 & below acquire() source

<-- 解 理 7: acquire() --> voidacquire() {
        if (isRecycled) {
            throw new IllegalStateException("Cannot acquire a recycled resource");
        }
        if(! Looper.getMainLooper().equals(Looper.myLooper())) { throw new IllegalThreadStateException("Must call acquire on the main thread"); } ++acquired; // Acquire () acquirement variable +1}Copy the code
  • Call when the image is not loadedrelease(), the variable decreases by 1

Tag 3 & for the above code below the release() source code

<-- analyze 8: release() --> voidrelease() {
        if (acquired <= 0) {
            throw new IllegalStateException("Cannot release a recycled or not yet acquired resource");
        }
        if(! Looper.getMainLooper().equals(Looper.myLooper())) { throw new IllegalThreadStateException("Must call release on the main thread");
        }
        if(--acquired == 0) { listener.onResourceReleased(key, this); Acquire (); acquire(); acquire(); The illustration is no longer used / / call the listener. OnResourceReleased () to release resources / / the listener = Engine object, Engine. OnResourceReleased () - > 9}}} < > analysis - analysis of 9: OnResourceReleased () - > public class Engine implements EngineJobListener, MemoryCache. ResourceRemovedListener, EngineResource.ResourceListener { private final MemoryCache cache; private final Map<Key, WeakReference<EngineResource<? >>> activeResources; . @Override public void onResourceReleased(Key cacheKey, EngineResource resource) { Util.assertMainThread(); activeResources.remove(cacheKey); // Step 1: Remove the cached image from the Active Resource weak reference cacheif(resource.isCacheable()) { cache.put(cacheKey, resource); // Step 2: Place the image cache in the LruResourceCache cache}else{ resourceRecycler.recycle(resource); }}... }Copy the code

So:

  • whenacquiredIf the variable is >0, the image is in use, that is, the image cache continues to store toactiveResourcesWeak reference cache
  • whenacquiredVariable = 0, that is, the image is no longer in use, the image cache Key fromactiveResourcesWeak references are removed from the cache and stored inLruResourceCacheThe cache

At this point, we have implemented:

  • Images in use use a weak-reference memory cache
  • Images not in use are usedLruCacheThe memory cache of the algorithm

conclusion


Step 10: Display images

  • The image is finally displayed after being written to the memory cache & disk cache
  • In the next loading, the image loading efficiency will be improved through the secondary cache

So far, Glide’s picture cache process is resolved.


Collect 5.

  • Take a picture of the wholeGlideSummary of image caching process

  • Summary of memory caching

    1. When reading from the memory cache, theLruCacheRead from the memory cache of the algorithmic mechanism, and read from the memory cache of the weak reference mechanism
    2. When writing to the memory cache, the memory cache of the weak reference mechanism is written first, and when the image is no longer in use, it is written toLruCacheMemory caching for algorithmic mechanisms
  • Summary of disk caching

    1. When reading the disk cache, the cache of the converted image is read first, and then the cache of the original image is read

Whether or not to read depends on the Settings that Glide uses the API

  1. When writing to the disk cache, write to the memory cache of the original image first, and then write to the memory cache

Whether or not to write depends on the Settings of the API used by Glide


6. Bonus note: Why is your Glide cache feature not working?

A. background

  • GlideThe implementation of memory & disk caching is based on image cachingKeyUniquely identify
  • Developers tend to keep their images in the cloud to reduce costs & security

Such as seven niuyun and so on.

  • In order to protect the customer’s picture resources, the picture cloud server will be in the pictureUrlAdd a token argument to the address
http://url.com/image.jpg?token=a6cvva6b02c670b0a
Copy the code
  • GlideWhen loading the image, add is usedtokenPicture of parametersUrlAddress asidParameter to generate a cache Key

B. the problem

  • For identificationtokenParameters may change, they are not set in stone
  • iftokenThe parameter changes, then the pictureUrlThen, the id parameter required to generate the cache key changes, that isThe cache Key also changes
  • This leads to the same picture, but becausetokenParameter changes, and the cache Key changes, so thatGlideThe cache function of the

The cache Key changes, that is, the current cache Key of the same image is not the same as the Key previously written to the cache, which means that the previous cache cannot be found according to the current cache Key when reading from the cache, making it invalid

C. Solutions

See article: Android Picture Loading Stuff: Why isn’t your Glide cache working?


7. To summarize

  • This paper mainly focuses onGlideThe picture cache function process & source analysis
  • Next, I will continue to source analysis of Glide’s other features. If you are interested, you can continue to pay attention to Carson_Ho’s Android development notes

Thumb up, please! Because your encouragement is the biggest power that I write!


Welcome to follow Carson_ho on wechat