zoukankan      html  css  js  c++  java
  • SDWebImage 加载显示 GIF 与性能问题

    支持 GIF 的图片组件 BBWebImage

    SDWebImage 加载显示 GIF 与性能问题

    SDWebImage 4.0 之前,可以用 UIImageView 显示 GIF 图。如果 SDWebImage 4.0 还这么做,只会显示静态图。SDWebImage 4.0 用 FLAnimatedImageView 通过 FLAnimatedImage 显示 GIF 图。本文的这两个库的版本分别为 SDWebImage 4.0.0 和 FLAnimatedImage 1.0.12。

    CocoaPods 安装

    pod 'SDWebImage'
    pod 'SDWebImage/GIF'
    

    一般用法

    用 FLAnimatedImageView 代替 UIImageView,显示 GIF。FLAnimatedImage 的 README.md 中介绍的用法

    FLAnimatedImage *image = [FLAnimatedImage animatedImageWithGIFData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif"]]];
    FLAnimatedImageView *imageView = [[FLAnimatedImageView alloc] init];
    imageView.animatedImage = image;
    imageView.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
    [self.view addSubview:imageView];
    

    千万别这么写,这段代码会阻塞主线程!在主线程通过 URL 获取 NSData,等下载结束才执行下一步。

    FLAnimatedImageView 的用法和 UIImageView 相似,初始化、设置 frame、添加到视图上、用 UIImage 给 image 属性赋值显示静态图片;不一样的是,用 FLAnimatedImage 给 animatedImage 属性赋值显示动态图片。以上代码的问题在于 FLAnimatedImage 的生成部分。

    SDWebImage 给 FLAnimatedImageView 添加了异步加载 GIF 的方法,与异步加载静态图片一样

    imageView.sd_setImage(with: url, placeholderImage: placeholder)
    

    如果显示少量的 GIF,这样写应该可以。然而,如果需要用 UITableView 或 UICollectionView 展示大量 GIF,这么写可能会有性能问题,滑动时发生顿卡。

    提升性能

    为了提高性能,可以指定 RunLoopMode,在 default mode 进行动画,在 tracking mode (比如 scroll view 滑动时) 停止动画

    imageView.runLoopMode = RunLoopMode.defaultRunLoopMode.rawValue
    

    我的代码中,这么写还是会有顿卡。查看 SDWebImage 的源码,发现了问题。

    sd_setImage(with:placeholderImage:) 会调用 sd_internalSetImageWithURL: 方法

    注意,sd_internalSetImageWithURL: 方法中的 setImageBlock 参数,在此生成 FLAnimatedImage。进一步查看 sd_internalSetImageWithURL: 方法的实现

    宏定义 dispatch_main_async_safe(block) 保证 block 在主线程中执行,其中包含 setImageBlock。因此 setImageBlock 在主线程中执行,也就是说 FLAnimatedImage 在主线程中生成,这一步比较耗时,阻塞主线程,造成顿卡。

    解决办法是,把 FLAnimatedImage 的生成放到子线程中。可以直接修改 SDWebImage 的源码,但不建议这么做。比较好的办法是,给 FLAnimatedImageView 添加方法

    extension FLAnimatedImageView {
        
        func setImage(with url: URL?, placeholderImage: UIImage?) {
            sd_internalSetImage(with: url, placeholderImage: placeholderImage, options: SDWebImageOptions(rawValue: 0), operationKey: nil, setImageBlock: { [weak self] (image, imageData) in
                guard let strongSelf = self else { return }
                
                let imageFormat = NSData.sd_imageFormat(forImageData: imageData)
                if imageFormat == .GIF {
                	// Enter global queue
                    DispatchQueue.global(qos: .userInteractive).async { [weak self] in
                    	// Create FLAnimatedImage in global queue
                        let animatedImage = FLAnimatedImage(animatedGIFData: imageData)
                        DispatchQueue.main.async { [weak self] in
                            guard let strongSelf = self else { return }
                            // Set image in main queue
                            strongSelf.animatedImage = animatedImage
                            strongSelf.image = nil
                        }
                    }
                } else {
                	// Set image in main queue
                    strongSelf.image = image
                    strongSelf.animatedImage = nil
                }
                }, progress: nil, completed: nil)
        }
    }
    

    同样调用 sd_internalSetImageWithURL: 方法,只是修改 setImageBlock 参数,在子线程中创建 FLAnimatedImage,然后在主线程中设置图片。

    这个方法也适用于静态图片。如果图片是静态图片,直接在主线程中设置图片,不用进入子线程。

    调用这个方法很简单

    imageView.setImage(with: url, placeholderImage: placeholder)
    

    这样写,UITableView 滑动就很流畅了。

    代码已上传 GitHub:https://github.com/Silence-GitHub/GIFDemo

    这个解决方案虽然能用,但是从设计的角度看,SDWebImage 使用 FLAnimatedImage 并不合适。有兴趣可以试试支持 GIF 的图片组件 BBWebImage

    转载请注明出处:http://www.cnblogs.com/silence-cnblogs/p/6682867.html

  • 相关阅读:
    android 75 新闻列表页面
    android 74 下载文本
    android 73 下载图片
    android 72 确定取消对话框,单选对话框,多选对话框
    android 71 ArrayAdapter和SimpleAdapter
    android 70 使用ListView把数据显示至屏幕
    maven如何将本地jar安装到本地仓库
    Centos6.7搭建ISCSI存储服务器
    解决maven打包编译出现File encoding has not been set问题
    MySQL 解决 emoji表情 的方法,使用utf8mb4 字符集(4字节 UTF-8 Unicode 编码)
  • 原文地址:https://www.cnblogs.com/silence-cnblogs/p/6682867.html
Copyright © 2011-2022 走看看