Disk caching doesn't work when using BitmapFactory.decodeStream() with GIFs
See original GitHub issueIt looks like when using OkHttp to hit an url that will return a GIF file, and then consuming the returned stream with BitmapFactory.decodeStream()
the file won’t be cached into disk.
If I understand correctly the way okhttp3.internal.cache.CacheInterceptor
works, it will use a okio.ForwardingSink
to communicate the stream interactions to the okhttp3.Cache
class, in order to signal its DiskLruCache.Editor
to commit()
to disk the stream that has just been exhausted and closed.
The problem seems to arise when consuming a GIF stream with BitmapFactory.decodeStream()
which will load a single frame and very likely doesn’t bother reading more than header+first frame from the stream, thus never triggering okhttp cache to write all the bytes to disk.
Is there any way to work around this or signal OkHttp to forcefully write its stream to disk cache?
I worked around this issue by writing this hacky Interceptor:
/**
* This interceptor is helpful if you want to force OkHttp to write the response to disk cache
* immediately after receiving it (instead of waiting for the response body stream to be consumed).
* Ideally it should only be used as a network interceptor (since application interceptors also
* intercept when fetching from cache)
*/
public class DiskCacheEnforcerOkHttpInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
Logger.verbose("Flushing OkHttp Response bytes to force disk caching.");
// by calling response.body().bytes() we force the stream to be consumed and thus cached to disk
ResponseBody newResponseBody = ResponseBody.create(response.body().contentType(), response.body().bytes());
return response.newBuilder().body(newResponseBody).build();
}
}
Issue Analytics
- State:
- Created 7 years ago
- Reactions:1
- Comments:8 (5 by maintainers)
Top GitHub Comments
Oooh, this is a tough case. I think your interceptor is actually a pretty great idea. You can make it even more efficient by using
BufferedSource.request()
:That’ll pull the data until it’s loaded either 10 MiB or the end of the file.
Alternately you could do a ForwardingSource that calls
skip()
onclose()
. That way you only skip the unwanted bytes after you’ve downloaded the image.No action to take here.