ReactNative取消滚动中图片下载

iOS原生UITableView滚动中图片取消下载

iOS原生图片库通常使用了SDWebImage,而UITableView的复用机制是创建一堆UITableViewCell,在滚动中不断地用新数据填充这些UITableViewCell;而SDWebImage实现的UIView+WebCacheOperation.m中,如果一个UIView已经存在了下载中的网络请求,那么就会取消掉这个网络请求:

- (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key {
    if (key) {
        // Cancel in progress downloader from queue
        SDOperationsDictionary *operationDictionary = [self sd_operationDictionary];
        id operation;
        
        @synchronized (self) {
            operation = [operationDictionary objectForKey:key];
        }
        if (operation) {
            if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]) {
                [operation cancel];
            }
            @synchronized (self) {
                [operationDictionary removeObjectForKey:key];
            }
        }
    }
}

所以UITableViewCell中使用SDWebImage的图片视图会在滚动中被复用从而取消下载,实现了滚动中取消图片下载的功能。

ReactNative中FlatList滚动中图片取消下载

ReactNative的FlatList是依赖DOM和key实现的各种优化,当FlatList中的elements每个都有不同的key时,滚动之后再次render的时候,出现的相同的key的element就不需要mutate,而上次显示的element这次没有显示则会从DOM中移除,在iOS原生反馈出来的就是这个element对应的RCTView从内存中被释放。

FlatList继承自VirtualizedList,VirtualizedList在滚动中移除不显示cell的流程如下图所示:

VirtualizedList移除不显示cell流程

那么取消滚动中超出屏幕范围的cell的图片下载就可以在cell的componentWillUnmount中来实现。项目中使用了react-native-img-cache做图片下载缓存,而react-native-img-cache同时提供了cancel方法来取消图片的下载:

ImageCache.get().cancel("https://i.ytimg.com/vi/yaqe1qesQ8c/maxresdefault.jpg");
FlatList的windowSize属性

FlatList的windowSize属性表示同时显示几屏,默认值是21,也就是当前屏,加上上10屏和下10屏。在实际中建议设置为3,即可以适当地移除显示屏幕范围之外的cell,来取消这些cell中图片的下载。

/**
   * Determines the maximum number of items rendered outside of the visible area, in units of
   * visible lengths. So if your list fills the screen, then `windowSize={21}` (the default) will
   * render the visible screen area plus up to 10 screens above and 10 below the viewport. Reducing
   * this number will reduce memory consumption and may improve performance, but will increase the
   * chance that fast scrolling may reveal momentary blank areas of unrendered content.
   */
FlatList的initialNumToRender属性

FlatList的initialNumToRender属性表示一开始要显示几个cell,建议根据实际情况设置为cell能够覆盖一屏的数量,该值默认为10。

/**
   * How many items to render in the initial batch. This should be enough to fill the screen but not
   * much more. Note these items will never be unmounted as part of the windowed rendering in order
   * to improve perceived performance of scroll-to-top actions.
   */
测试

为了方便观察cell超过windowSize就会被移除,实验中设置windowSize为,同时设置initialNumToRender为4,测试代码如下:

import {CachedImage, ImageCache} from "react-native-img-cache";

class ImageTT extends React.Component {

  componentWillUnmount() {
    ImageCache.get().cancel(this.props.imageUrl);
  }

  render() {
    return (
      
        
      
    );
  }
}

export default function App() {
  return (
    
       }
        keyExtractor={item => item.id}
        windowSize={1}
        initialNumToRender={4}
      />
    
  );
}

测试数据中url先试用伪造的url,以便于观察取消下载的调用情况,下面是componentWillUnmount中的断点信息在滚动中在控制台的打印信息:

componentWillUnmount调用打印

伪造的url数据时从“https://www.abc.com/1.jpg”开始的,在图片上滚动之后的取消下载却是从“https://www.abc.com/5.jpg”开始的,这是由于我们设置的initialNumToRender为4,所以头4个cell永远不会被移除,所以是从“https://www.abc.com/5.jpg”开始移除;这也方便了“Go to top”这个功能。

将数据换为实际的图片URL进行测试结果如下图所示:

测试.png

其中红色部分是一开始的4个cell对应的图片下载,随着滚动后续cell中的图片取消了下载,但是最开始的4个下载一直没有受到影响,而最下面的下载则是在windowSize范围之内的cell的下载。

总结

  • 实现ReactNative在滚动中取消下载依靠FlatList的移除cell的机制,在cell被移除时添加取消对应图片下载操作来完成这一功能。
  • 如果使用了react-native-img-cache,那么可以在cell的componentWillUnmount中使用react-native-img-cache提供的cancel方法来取消下载。
  • 如果使用了react-native-fast-image,那么可以在iOS原生端扩展对应的RCTView在dealloc时取消对应url下载。
  • 结合项目实际情况调整FlatList的windowSize和initialNumToRender属性。

你可能感兴趣的:(ReactNative取消滚动中图片下载)