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<SDWebImageOperation> 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 (
      <View>
        <CachedImage 
          style={{
            width: 320, 
            height: 240, 
          }}
          source={{uri: this.props.imageUrl}} />
      </View>
    );
  }
}

export default function App() {
  return (
    <SafeAreaView style={styles.container}>
      <FlatList
        data={DATA}
        renderItem={({ item }) => <ImageTT imageUrl={item.url} />}
        keyExtractor={item => item.id}
        windowSize={1}
        initialNumToRender={4}
      />
    </SafeAreaView>
  );
}

测试数据中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属性。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容