49

We are trying to preload images into cache memory to load them later (the images are located in the Asset folder of the application)

What we tried:

Glide.with(this)
    .load(pictureUri)
    .diskCacheStrategy(DiskCacheStrategy.ALL);

Glide.with(this)
    .load(picture_uri)
    .diskCacheStrategy(DiskCacheStrategy.ALL)
    .preload();

The issue: Images are cached only when we are trying to load/display them: They have to be loaded in memory before so that they appear faster.

Glide.with(this)
    .load(picture_uri)
    .into(imageView);

We also tried to use a GlideModule to increase the CacheMemory size:

public class GlideModule implements com.bumptech.glide.module.GlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder
        builder.setMemoryCache(new LruResourceCache(100000));
    }

    @Override
    public void registerComponents(Context context, Glide glide) {
    }
}

In the manifest:

 <meta-data android:name=".GlideModule" android:value="GlideModule"/>

Nothing is working so far. Any idea?


We trying to use an invisible 1 dp imageView, but the result is the same:

for(Drawing drawing: getDrawingsForTab(tab)){

    Glide.with(this)
            .load(drawing.getImage().toUri())
            .dontAnimate()
            .diskCacheStrategy(DiskCacheStrategy.ALL)
            .into(mPreloadCacheIv);

    for(Picture picture : getPictures()){

        Glide.with(this)
                .load(picture.getPicture().toUri())
                .dontAnimate()
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .into(mPreloadCacheIv);
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
An-droid
  • 6,433
  • 9
  • 48
  • 93
  • Maybe you could previously load then in an invisible imageView when it's appropriate. – Laurent Russier Jun 22 '16 at 09:56
  • 1
    I updated the question with your advice. It's still not working. Glide documentation is not very clear on that subject :/ – An-droid Jun 22 '16 at 10:14
  • 1
    I have not used Glide. If your images are assets, I am not quite certain why you are configuring `diskCacheStrategy()`, as the images are already on disk. Are you sure that your memory cache is being recognized by Glide? – CommonsWare Jul 01 '16 at 14:17
  • From the assets the images take too long to load into the ImageView. Once they have been loaded once into memory it's immediat. What i'm trying to acheive is the second behavior for the first time the image is loaded. Do I have a way of knowing in which state is the memory cache ? – An-droid Jul 04 '16 at 08:08

5 Answers5

47

Use the following code to cache images without displaying them

  1. using the downloadOnly method if you are looking to download images from the web and store them in the diskCache:

    FutureTarget<File> future = Glide.with(applicationContext)
        .load(yourUrl)
        .downloadOnly(500, 500);
    
  2. using preload method if you want to load them into the Memory Cache.

    Glide.with(context)
            .load(url)
            .preload(500, 500);
    

You can later use the cached images using

Glide.with(yourFragment)
    .load(yourUrl)
    .into(yourView);

Vinay W
  • 9,912
  • 8
  • 41
  • 47
  • Note that the images are located in the Asset folder of the app, will it still work ? – An-droid Jul 01 '16 at 13:28
  • I guessed that you want to download the images from web. The API seems to be for "downloadOnly" so i guess the answer is no. Regardless, as i understand, you are looking to load images from assets into the MemoryCache? – Vinay W Jul 01 '16 at 13:32
  • Yes that's the case, I didn't spécify it in the question (I'll edit it). I just need the images to be available into memory for a faster loading and avoid 1, 2 secs between the click and their apparence. Would you know any trick to do that ? With glide or not ? – An-droid Jul 01 '16 at 13:35
  • Updated the answer – Vinay W Jul 01 '16 at 13:38
  • Could you detail more the answer for exemple the construction of the url/uri/path to get the asset. I already tried preload as described in the question and it's not working – An-droid Jul 01 '16 at 13:42
  • how do you know it's not working? How can you tell that the image loaded from the memory cache or disk? – Vinay W Jul 01 '16 at 13:51
  • 1
    When I say it's not working, I mean the image takes the same amount of time to load. Yes I tried to use a glide module with some LruResourceCache as described in the question – An-droid Jul 01 '16 at 13:55
  • 2
    You should use `GlideApp.with(yourFragment).load(yourUrl).fitCenter().asBitmap().preload();` to fix cache missies. – EmmanuelMess Dec 10 '17 at 18:00
  • where can i find downloaded images? – Vivek Barai Jun 07 '18 at 08:20
  • 2
    What helped me in my case: `Glide.with(this).asDrawable().load(url).fitCenter().preload(imageView.width, imageView.height)` Thank to @EmmanuelMess for the clue. – demaksee Apr 13 '20 at 11:09
24

The best option is to handle caching yourself, it gives you more control & should be easy as you already know what bitmaps are to be loaded.

First: Setup a LruCache

LruCache<String, Bitmap> memCache = new LruCache<>(size) {
    @Override
    protected int sizeOf(String key, Bitmap image) {
        return image.getByteCount()/1024;
    }
};

Second: Load the bitmaps to the LruCache

Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x; //width of screen in pixels
int height = size.y;//height of screen in pixels
Glide.with(context)
    .load(Uri.parse("file:///android_asset/imagefile"))
    .asBitmap()
    .fitCenter() //fits given dimensions maintaining ratio
    .into(new SimpleTarget(width,height) {
        // the constructor SimpleTarget() without (width, height) can also be used.
        // as suggested by, An-droid in the comments
        @Override
        public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) {
            memCache.put("imagefile", resource);
        }
    });

Third: Use the cached bitmaps

Bitmap image = memCache.get("imagefile");
if (image != null) {
    //Bitmap exists in cache.
    imageView.setImageBitmap(image); 
} else {
    //Bitmap not found in cache reload it 
    Glide.with(context)
         .load(Uri.parse("file:///android_asset/imagefile"))
         .into(imageView);
}
Sakchham
  • 1,689
  • 12
  • 22
  • How would you calculate the size of the Lru cache ? Knowing i'll cache several images ? – An-droid Jul 06 '16 at 09:04
  • 2
    It isn't a good practice to flood all of your memory with bitmaps, ideally you should not exceed more than a quarter of the memory allocated to your application `(int) (Runtime.getRuntime().maxMemory() / (1024 * 4))` if you are needing a cache larger than that, you should try a different architectural approach. – Sakchham Jul 06 '16 at 09:21
  • Another thing, the sizeOf(String key, Bitmap image) method is unknown to glide. It only have getSize(Object item) ? – An-droid Jul 06 '16 at 09:33
  • the LruCache I'm using is `android.util.LruCache` – Sakchham Jul 06 '16 at 09:38
  • I used com.bumptech.glide.util.LruCache and it seems to work. The only thing that is missing is to get width and height to size the image properly. The image should be in full screen but keeping it's ratio – An-droid Jul 06 '16 at 09:47
  • 3
    Your response is good, for information it's also possible to use new SimpleTarget() withou specifying values which keep the original size. That's what i've done:) – An-droid Jul 06 '16 at 11:27
  • 1
    Just want to mention that it's likely unnecessary for most cases to implement your own LruCache when using the latest version of Glide, as it has it's own disk-based LRU cache. See here: https://bumptech.github.io/glide/doc/configuration.html#disk-cache This is also configurable so you can manage how much memory to allocate to the Glide cache. – w3bshark Oct 24 '18 at 14:16
13

Preload with Glide

Glide version 4.6.1

RequestOptions requestOptions = RequestOptions
        .diskCacheStrategy(DiskCacheStrategy.ALL);

Glide.with(appContext)
        .asBitmap()
        .load(model)
        .apply(requestOptions)
        .submit();
yoAlex5
  • 29,217
  • 8
  • 193
  • 205
4

As the downloadOnly function is deprecated to cache on Disk:

Glide.with(ctx)
        .load("Image URL")
        .downloadOnly(500, 500)

We can now use:

Glide.with(ctx)
        .downloadOnly()
        .load("Image URL")
        .submit(500, 500)
shaarawy
  • 169
  • 7
  • If you look at `downloadOnly` signature you'll see that it is caching the image in `disk cache` and skip `memory cache` – Biscuit May 25 '20 at 11:14
  • 1
    it is better to load it in the disk first not to overload the memory with image resources – shaarawy May 26 '20 at 13:10
-1
//i can give you a solution

/**
 * 1.reflect some objects inside Glide
 */
fun prepareGlideObjects() {
    if (!enableFunctions || atomicPrepare.getAndSet(true)) {
        return
    }
    var t = LogTime.getLogTime()
    glide = Glide.get(BasicConfig.getInstance().appContext)
    if (diskCache == null) {
        val engine = getObject(glide, "engine")
        val diskCacheProvider = getObject(engine, "diskCacheProvider")
        val method = diskCacheProvider!!::class.java.getDeclaredMethod("getDiskCache")
        method.isAccessible = true
        diskCache = method.invoke(diskCacheProvider) as DiskCache
    }
    if (arrayPool == null) {
        arrayPool = getObject(glide, "arrayPool") as ArrayPool
    }
    if (decoder == null) {
        val registry = getObject(glide, "registry") as Registry
        val decoderRegistry = getObject(registry, "decoderRegistry") as ResourceDecoderRegistry
        val map = getObject(decoderRegistry, "decoders") as HashMap<*, *>
        val list = map["Bitmap"] as List<*>
        val o = list[0]
        decoder = getObject(o, "decoder") as ByteBufferBitmapDecoder
    }
    Log.debug(TAG, "prepareGlideObjects:" + LogTime.getElapsedMillis(t))
    try {
        t = LogTime.getLogTime()
        //首次打开diskCache 耗时较大,此处是提前打开文件索引
        val url = GlideUrl("http://xx.cdn.yy.com/fake_pic.jpg")
        val dataCacheKey = DataCacheKey(url, EmptySignature.obtain())
        diskCache?.get(dataCacheKey)
        Log.debug(TAG, "_load_fake_pic:" + LogTime.getElapsedMillis(t))
    } catch (e: Throwable) {
        Log.error(TAG, "cold load failed:$e")
    }
}

/**
 *2.load bitmap-file from diskCache
 */
fun loadBitmap(url: String) {
    val gUrl = GlideUrl(url:String)
    val dataCacheKey = DataCacheKey(gUrl, EmptySignature.obtain())
    val file = diskCache?.get(dataCacheKey)
}

//3.decode bitmap from file
private fun extractBitmapFromFile(url: String, file: File) {
    try {
        val dimen = getDimensionFromUrl(url)
        val result = decoder?.decode(ByteBufferUtil.fromFile(file), dimen[0], dimen[1],
                Options()) as BitmapResource?
        result!!.initialize()
        //simple bitmap cache
        bitmapMap[url] = result.get()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            Log.debug(TAG, "allocationByteCount:" +
                    bitmapMap[url]!!.allocationByteCount / 1024.0)
        }
    } catch (e: Throwable) {
        Log.error(TAG, "init result failed:$e")
    }
}

//4.decode file from http-stream
private fun decodeHttpStream() {
    val uri = GlideUrl(call?.request()?.url().toString())
    val contentLength = Preconditions.checkNotNull(responseBody).contentLength()
    val stream = ContentLengthInputStream.obtain(responseBody.byteStream(),
            contentLength)
    if (arrayPool == null) {
        //re prepare
        arrayPool = glide?.arrayPool
    }
    val encoder = StreamEncoder(arrayPool)
    val writer = DataCacheWriter(encoder, stream, Options())
    val originalKey = DataCacheKey(uri, EmptySignature.obtain())
    //ready,此处可以用来监控文件字节流写入本地文件的时间
    diskCache?.put(originalKey, writer)
    val file = diskCache?.get(uri)
}

//5.after these jobs done, load a bitmap from diskCache,it takes just 10ms。

dong sheng
  • 266
  • 3
  • 10