美文网首页
探究react-native 源码的图片缓存-- 自定义图片缓存

探究react-native 源码的图片缓存-- 自定义图片缓存

作者: 请叫我啊亮 | 来源:发表于2020-07-03 16:01 被阅读0次

    最近一个项目RN版本是0.61,因里面有个图片浏览功能,要做一个清理缓存的功能。一番捣鼓后功能解决,记录如下
    找到的清理缓存组建是react-native-http-cache,因为该组建长期没人维护android编译不过,本人又不善长android,遂找了个进化版react-native-http-cache3。这个在安卓上面需要更改两个地方才可正常工作,不做讨论,本文主要是讲ios上面。

    iOS在解决了2个bug之后这个组建也能使用,但是发现ios导给rn的方法getImageCacheSize以及clearImageCache都只是空实现,没有具体内容。原因下面解释。

    三年前我写的分析RN端图片缓存的策略(https://www.jianshu.com/p/c7376db9b7ec),当时图片是没有磁盘缓存的,内存缓存也无效。现在再看下新的RN版本图片缓存相关代码,经过测试发现,对解压后2M以内的图片,内存缓存生效。磁盘缓存依旧没有。正因为没有磁盘缓存,所谓的清理图片缓存也就不存在,于是方法为空实现也就能理解了。

    本人项目中有图片浏览功能,当预览图片时图片是高清的原图,比较大,按照rn默认的行为图片不做缓存,那么每次预览时都会去下载,很缓慢,影响体验。而且因为图片远大于2M内存缓存也无法生效,效果很差劲。这里需要自定义图片的缓存

    网上搜索了一圈发现都是解决方案都是使用react-native-img-cache,但是要求使用特定的<CachedImage />图片组件,这样是不太理想的,比如我这里使用的图片预览组件,其内部使用的是Animate.Image显示图片,总不能去别个组件内部更改为CachedImage吧。

    翻看RN图片加载相关的代码,发现了关键地方。在RCTImageLoaderProtocol.h这个图片加载相关的协议里面发现

    /**
     * Allows developers to set their own caching implementation for
     * decoded images as long as it conforms to the RCTImageCache
     * protocol. This method should be called in bridgeDidInitializeModule.
     */
    - (void)setImageCache:(id<RCTImageCache>)cache;
    

    很明显,这里可以让开发者自定义图片的缓存类,只需实现RCTImageCache协议即可。

    很简单,我使用SDWebImage实现了这个协议

    #import "PSImageCache.h"
    #import <SDWebImage/SDImageCache.h>
    
    @implementation PSImageCache
    
    - (UIImage *)imageForUrl:(NSString *)url
                        size:(CGSize)size
                       scale:(CGFloat)scale
                  resizeMode:(RCTResizeMode)resizeMode{
      if (!url) return nil;
      return [[SDImageCache sharedImageCache] imageFromCacheForKey:url];
    }
    
    - (void)addImageToCache:(UIImage *)image
                        URL:(NSString *)url
                       size:(CGSize)size
                      scale:(CGFloat)scale
                 resizeMode:(RCTResizeMode)resizeMode
                   response:(NSURLResponse *)response{
      if (!image || !url) return;
      [[SDImageCache sharedImageCache] storeImage:image forKey:url completion:nil];
    }
    @end
    
    

    现在只需要在一个合适的时机,将自定义的PSImageCache类赋值给RCTImageLoader即可。

    多方实验,如下最佳实践。在didFinishLaunchingWithOptions中

      // 监听RCTImageLoader模块加载完毕,自定义imageCache为sdwebimage缓存图片
      [[NSNotificationCenter defaultCenter] addObserverForName:RCTDidInitializeModuleNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
        RCTImageLoader *imageLoader = note.userInfo[@"module"];
        if ([imageLoader isKindOfClass:[RCTImageLoader class]]) {
          [imageLoader setImageCache:[PSImageCache new]];
        }
      }];
    

    现在图片缓存已经走Sdwebcache通道了,一切正常。最上面说的清理缓存的两个空方法需要更改下。将Podfile中倒入的react-native-http-cache3删除,RNHttpCache文件挪到本地文件,修改getImageCacheSize和clearImageCache方法

    RCT_EXPORT_METHOD(getImageCacheSize:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
    {
        resolve(@([[SDImageCache sharedImageCache] totalDiskSize]));
    }
    
    RCT_EXPORT_METHOD(clearImageCache:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
    {
      [[SDImageCache sharedImageCache] clearDiskOnCompletion:^{
        resolve(nil);
      }];
    }
    

    大功告成!

    相关文章

      网友评论

          本文标题:探究react-native 源码的图片缓存-- 自定义图片缓存

          本文链接:https://www.haomeiwen.com/subject/pamsqktx.html