glide图片加载失败空白的处理

问题背景

最近升级glide4.x后偶尔会有用户反馈应用升级后打开app图片无法正常显示,打开几个页面仍是如此。在glide3.x版本有碰到过类似问题,在glide4.x修复后总结一下,看看有没有人碰到类似问题。在15年时公司app 图片加载框架开始由Android-Universal-Image-Loader迁移到glide。迁移后数据表现十分良好。但是也偶尔有用户反馈图片无法加载,卸载重新安装或者重启后恢复正常。

问题分析

联系用户抓取用户手机的网络请求后发现当图片加载时均会发起网络请求图片资源,且同一url图片多次加载会请求多次。我们知道图片加载框架一般流程是图片没有被缓存,网络请求资源再缓存,下次请求直接走缓存逻辑。,初步推测是缓存逻辑有问题,后面拿到log发现确实如此。

12-29 15:58:49.551 9289-9422/? V/DecodeJob: Decoded transformed from cache in 0.5225, key: EngineKey{http://b1.hucdn.com/upload/show/1512/07/53440550730659_640x300.jpg!640x300.jpg+com.bumptech.glide.f.b@43199d08+[1080x506]+''+'ImageVideoBitmapDecoder.com.bumptech.glide.load.resource.bitmap'+''+'BitmapEncoder.com.bumptech.glide.load.resource.bitmap'+''+''}
12-29 15:58:49.551 9289-9422/? V/DecodeJob: Transcoded transformed from cache in 0.06958299999999999, key: EngineKey{http://b1.hucdn.com/upload/show/1512/07/53440550730659_640x300.jpg!640x300.jpg+com.bumptech.glide.f.b@43199d08+[1080x506]+''+'ImageVideoBitmapDecoder.com.bumptech.glide.load.resource.bitmap'+''+'BitmapEncoder.com.bumptech.glide.load.resource.bitmap'+''+''}
12-29 15:58:49.551 9289-9422/? V/DecodeJob: Decoded source from cache in 0.43432299999999996, key: EngineKey{http://b1.hucdn.com/upload/show/1512/07/53440550730659_640x300.jpg!640x300.jpg+com.bumptech.glide.f.b@43199d08+[1080x506]+''+'ImageVideoBitmapDecoder.com.bumptech.glide.load.resource.bitmap'+''+'BitmapEncoder.com.bumptech.glide.load.resource.bitmap'+''+''}
12-29 15:58:49.551 9289-9422/? V/DecodeJob: Transformed resource from source in 0.055364, key: EngineKey{http://b1.hucdn.com/upload/show/1512/07/53440550730659_640x300.jpg!640x300.jpg+com.bumptech.glide.f.b@43199d08+[1080x506]+''+'ImageVideoBitmapDecoder.com.bumptech.glide.load.resource.bitmap'+''+'BitmapEncoder.com.bumptech.glide.load.resource.bitmap'+''+''}
12-29 15:58:49.551 9289-9422/? V/DecodeJob: Transcoded transformed from source in 0.236563, key: EngineKey{http://b1.hucdn.com/upload/show/1512/07/53440550730659_640x300.jpg!640x300.jpg+com.bumptech.glide.f.b@43199d08+[1080x506]+''+'ImageVideoBitmapDecoder.com.bumptech.glide.load.resource.bitmap'+''+'BitmapEncoder.com.bumptech.glide.load.resource.bitmap'+''+''}
12-29 15:58:49.551 9289-9289/? V/GenericRequest: Got onSizeReady in 0.065417 this: 1167623000
12-29 15:58:49.551 9289-9289/? V/GenericRequest: finished setup for calling load in 0.39494799999999997 this: 1167623000
12-29 15:58:49.551 9289-9289/? V/GenericRequest: Resource ready in 1.48099 size: 0.03662109375 fromCache: true this: 1167623000
12-29 15:58:49.551 9289-9289/? V/Engine: Loaded resource from active resources in 1.0822399999999999ms, key: EngineKey{http://s0.husor.cn/image/app/img_mj_icon.jpg+com.bumptech.glide.f.b@43199d08+[33x33]+''+'ImageVideoBitmapDecoder.com.bumptech.glide.load.resource.bitmap'+''+'BitmapEncoder.com.bumptech.glide.load.resource.bitmap'+''+''}
12-29 15:58:49.551 9289-9289/? V/GenericRequest: finished onSizeReady in 2.30651 this: 1167623000
12-29 15:58:49.551 9289-9289/? V/GenericRequest: finished run method in 2.5901039999999997 this: 1167623000
12-29 15:58:49.561 9289-9453/? V/DecodeJob: Fetched data in 98.300782, key: EngineKey{http://b1.hucdn.com/upload/show/1512/28/88559748030011_640x300.jpg!640x300.jpg+com.bumptech.glide.f.b@43199d08+[1080x506]+''+'ImageVideoBitmapDecoder.com.bumptech.glide.load.resource.bitmap'+''+'BitmapEncoder.com.bumptech.glide.load.resource.bitmap'+''+''}
12-29 15:58:49.561 9289-9453/? D/DecodeJob: Failed to find file to write to disk cache
    java.io.FileNotFoundException: /storage/emulated/0/Android/data/com.husor.beibei/cache/glide/5a636e024b98a2b723472865a2690a9ac38f38a5a77dba9e51d2688b17cba8ee.0.tmp: open failed: EBUSY (Device or resource busy)
        at libcore.io.IoBridge.open(IoBridge.java:409)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:88)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:73)
        at com.bumptech.glide.load.engine.c.a(DecodeJob.java:294)
        at com.bumptech.glide.load.engine.d.a(DecodeJob.java:269)
        at com.bumptech.glide.load.engine.a.j.a(DiskLruCacheWrapper.java:98)
        at com.bumptech.glide.load.engine.a.b(DecodeJob.java:201)
        at com.bumptech.glide.load.engine.a.a(DecodeJob.java:187)
        at com.bumptech.glide.load.engine.a.e(DecodeJob.java:177)
        at com.bumptech.glide.load.engine.a.c(DecodeJob.java:128)
        at com.bumptech.glide.load.engine.EngineRunnable.f(EngineRunnable.java:122)
        at com.bumptech.glide.load.engine.EngineRunnable.d(EngineRunnable.java:101)
        at com.bumptech.glide.load.engine.EngineRunnable.run(EngineRunnable.java:58)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
        at java.lang.Thread.run(Thread.java:841)
        at com.bumptech.glide.load.engine.executor.a$1.run(FifoPriorityThreadPoolExecutor.java:118)
     Caused by: libcore.io.ErrnoException: open failed: EBUSY (Device or resource busy)
        at libcore.io.Posix.open(Native Method)
        at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
        at libcore.io.IoBridge.open(IoBridge.java:393)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:88) 
        at java.io.FileOutputStream.<init>(FileOutputStream.java:73) 
        at com.bumptech.glide.load.engine.c.a(DecodeJob.java:294) 
        at com.bumptech.glide.load.engine.d.a(DecodeJob.java:269) 
        at com.bumptech.glide.load.engine.a.j.a(DiskLruCacheWrapper.java:98) 
        at com.bumptech.glide.load.engine.a.b(DecodeJob.java:201) 
        at com.bumptech.glide.load.engine.a.a(DecodeJob.java:187) 
        at com.bumptech.glide.load.engine.a.e(DecodeJob.java:177) 
        at com.bumptech.glide.load.engine.a.c(DecodeJob.java:128) 
        at com.bumptech.glide.load.engine.EngineRunnable.f(EngineRunnable.java:122) 
        at com.bumptech.glide.load.engine.EngineRunnable.d(EngineRunnable.java:101) 
        at com.bumptech.glide.load.engine.EngineRunnable.run(EngineRunnable.java:58) 
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422) 
        at java.util.concurrent.FutureTask.run(FutureTask.java:237) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
        at java.lang.Thread.run(Thread.java:841) 
        at com.bumptech.glide.load.engine.executor.a$1.run(FifoPriorityThreadPoolExecutor.java:118) 
12-29 15:58:49.561 9289-9453/? V/DecodeJob: Wrote source to cache in 5.031353, key: EngineKey{http://b1.hucdn.com/upload/show/1512/28/88559748030011_640x300.jpg!640x300.jpg+com.bumptech.glide.f.b@43199d08+[1080x506]+''+'ImageVideoBitmapDecoder.com.bumptech.glide.load.resource.bitmap'+''+'BitmapEncoder.com.bumptech.glide.load.resource.bitmap'+''+''}
12-29 15:58:49.571 9289-9453/? V/DecodeJob: Transformed resource from source in 0.074219, key: EngineKey{http://b1.hucdn.com/upload/show/1512/28/88559748030011_640x300.jpg!640x300.jpg+com.bumptech.glide.f.b@43199d08+[1080x506]+''+'ImageVideoBitmapDecoder.com.bumptech.glide.load.resource.bitmap'+''+'BitmapEncoder.com.bumptech.glide.load.resource.bitmap'+''+''}
12-29 15:58:49.571 9289-9453/? V/DecodeJob: Transcoded transformed from source in 0.059061999999999996, key: EngineKey{http://b1.hucdn.com/upload/show/1512/28/88559748030011_640x300.jpg!640x300.jpg+com.bumptech.glide.f.b@43199d08+[1080x506]+''+'ImageVideoBitmapDecoder.com.bumptech.glide.load.resource.bitmap'+''+'BitmapEncoder.com.bumptech.glide.load.resource.bitmap'+''+''}
12-29 15:58:49.601 9289-9289/? D/GenericRequest: load failed

图片在加载过程中出现了IO异常,无法正常读写数据。

出问题的逻辑在com.bumptech.glide.load.engine.DecodeJob中的cacheAndDecodeSourceData方法:

private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {
        long startTime = LogTime.getLogTime();
        SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data);
        diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Wrote source to cache", startTime);
        }

        startTime = LogTime.getLogTime();
        Resource<T> result = loadFromCache(resultKey.getOriginalKey());
        if (Log.isLoggable(TAG, Log.VERBOSE) && result != null) {
            logWithTimeAndKey("Decoded source from cache", startTime);
        }
        return result;
    }

此时网络图片数据由于IO异常无法被正常缓存,之后loadFromCache返回null。

找到原因之后,顺手给glide提了一个issue反馈了这个问题。

解决方法

后来想了一下,这种情况下图片网络请求已经发起成功,流量已经消耗,我直接解析网络返回的数据然后返回结果就好。

如果出现这种异常,我们就直接decode网络请求到的数据。

代码改动如下,glide3.7版本

private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {
        long startTime = LogTime.getLogTime();
        SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data);
        diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Wrote source to cache", startTime);
        }

        startTime = LogTime.getLogTime();
        Resource<T> result = loadFromCache(resultKey.getOriginalKey());
        if (Log.isLoggable(TAG, Log.VERBOSE) && result != null) {
            logWithTimeAndKey("Decoded source from cache", startTime);
        }

        //add by huangyanan when load cache failed then decode source data. start
        if (result == null) {
            startTime = LogTime.getLogTime();
            result = loadProvider.getSourceDecoder().decode(data, width, height);
//            Utils.reportError(null, "kGlideImageLoadCacheFailed", null);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Cache failed,Decoded from source", startTime);
            }
        }
        //add by huangyanan end

        return result;
    }

推荐阅读更多精彩内容