flutter图片内存优化

作者: xmb | 来源:发表于2021-03-17 12:05 被阅读0次

方法一

按照给定尺寸进行图片的解码,而不是解码整个图片的尺寸,用来减少内存的占用。

官方文档:
https://api.flutter.dev/flutter/painting/ResizeImage-class.html

官方说明:
Instructs Flutter to decode the image at the specified dimensions instead of at its native size.

This allows finer control of the size of the image in ImageCache and is generally used to reduce the memory footprint of ImageCache.

The decoded image may still be displayed at sizes other than the cached size provided here.

使用:

Image(
                      image: ResizeImage(
                        NetworkImage('https://img-dev.xinxigu.com.cn/s1/2021/1/18/6e19c84b1b4aeb416bdee40615aa9854.jpg'),
                        width: AdaptUtils.pxW(150).toInt(),
                        height: AdaptUtils.pxW(150).toInt(),
                      ),
                    ),

方法二

三方库:cached_network_image 限2.5.0之后版本才可用
设定最大的缓存宽度和高度this.maxWidthDiskCachethis.maxHeightDiskCache

image.png
  CachedNetworkImage({
    Key key,
    @required this.imageUrl,
    this.httpHeaders,
    this.imageBuilder,
    this.placeholder,
    this.progressIndicatorBuilder,
    this.errorWidget,
    this.fadeOutDuration = const Duration(milliseconds: 1000),
    this.fadeOutCurve = Curves.easeOut,
    this.fadeInDuration = const Duration(milliseconds: 500),
    this.fadeInCurve = Curves.easeIn,
    this.width,
    this.height,
    this.fit,
    this.alignment = Alignment.center,
    this.repeat = ImageRepeat.noRepeat,
    this.matchTextDirection = false,
    this.cacheManager,
    this.useOldImageOnUrlChange = false,
    this.color,
    this.filterQuality = FilterQuality.low,
    this.colorBlendMode,
    this.placeholderFadeInDuration,
    this.memCacheWidth,
    this.memCacheHeight,
    this.cacheKey,
    this.maxWidthDiskCache,
    this.maxHeightDiskCache,

使用:

CachedNetworkImage(
                      imageUrl: AppUtils.processImageUrl(url: coverUrl) ?? AppURL.defaultImageRectangle,
                      width: AdaptUtils.pxW(150),
                      height: AdaptUtils.pxW(150),
                      fit: BoxFit.cover,
                      placeholder: AppURL.placeholderRectangle(
                        width: AdaptUtils.pxW(150),
                        height: AdaptUtils.pxW(150),
                      ),
                      maxWidthDiskCache: AdaptUtils.pxW(150 * 2).toInt(),
                      maxHeightDiskCache: AdaptUtils.pxW(150 * 2).toInt(),
                    ),

方法三

从相册选取图片,展示时使用指定尺寸宽高进行处理。
使用三方库:

  # 仿微信资源选择器
  wechat_assets_picker: ^4.2.0

  # 仿微信拍照
  wechat_camera_picker: ^1.2.1

使用自定义provider来指定所需图片的宽高:

  /// The item builder for images and video type of asset.
  /// 图片和视频资源的部件构建
  /// 缩略图视图
  static Widget thumbImageItemBuilder(
      BuildContext context,
      AssetEntity asset, // 图片资源数据
      double thumbSizeWidth, // 缩略图宽,同为图片展示宽
      double thumbSizeHeight, // 缩略图高,同为图片展示高
      BoxFit fit, // 图片展示方式
      ) {
    final AssetEntityImageProvider imageProvider = AssetEntityImageProvider(
      asset,
      isOriginal: false,
      thumbSize: [int.parse('${thumbSizeWidth.toStringAsFixed(0)}'), int.parse('${thumbSizeWidth.toStringAsFixed(0)}')],
    );
    return RepaintBoundary(
      child: Image(
        width: thumbSizeWidth,
        height: thumbSizeHeight,
        image: imageProvider,
        fit: fit,
      ),
    );
  }

AssetEntityImageProvider传入宽高和图片原图AssetEntity数据。
providerkey.entity.thumbDataWithSize方法:

  Future<ui.Codec> _loadAsync(
    AssetEntityImageProvider key,
    DecoderCallback decode,
  ) async {
    assert(key == this);
    Uint8List data;
    if (isOriginal ?? false) {
      if (imageFileType == ImageFileType.heic) {
        data = await (await key.entity.file).readAsBytes();
      } else {
        data = await key.entity.originBytes;
      }
    } else {
      data = await key.entity.thumbDataWithSize(thumbSize[0], thumbSize[1]);
    }
    return decode(data);
  }

进入entitythumbDataWithSize方法:

  /// get thumb with size
  Future<Uint8List> thumbDataWithSize(
    int width,
    int height, {
    ThumbFormat format = ThumbFormat.jpeg,
    int quality = 100,
  }) {
    assert(width > 0 && height > 0, "The width and height must better 0.");
    assert(format != null, "The format must not be null.");
    assert(quality > 0 && quality <= 100, "The quality must between 0 and 100");

    /// Return null if asset is audio or other type, because they don't have such a thing.
    if (type == AssetType.audio || type == AssetType.other) {
      return null;
    }

    return PhotoManager._getThumbDataWithId(
      id,
      width: width,
      height: height,
      format: format,
      quality: quality,
    );
  }

进入_getThumbDataWithId方法中,

  static _getThumbDataWithId(
    String id, {
    int width = 150,
    int height = 150,
    ThumbFormat format = ThumbFormat.jpeg,
    int quality = 100,
  }) {
    return _plugin.getThumb(
      id: id,
      width: width,
      height: height,
      format: format,
      quality: quality,
    );
  }

进入getThumb:

  Future<Uint8List> getThumb({
    @required String id,
    int width = 100,
    int height = 100,
    ThumbFormat format,
    int quality,
  }) {
    return _channel.invokeMethod("getThumb", {
      "width": width,
      "height": height,
      "id": id,
      "format": format.index,
      "quality": quality,
    });
  }

调用iOS原生的获取图片方法,

if ([call.method isEqualToString:@"getThumb"]) {
        NSString *id = call.arguments[@"id"];
        NSUInteger width = [call.arguments[@"width"] unsignedIntegerValue];
        NSUInteger height = [call.arguments[@"height"] unsignedIntegerValue];
        NSUInteger format = [call.arguments[@"format"] unsignedIntegerValue];
        NSUInteger quality = [call.arguments[@"quality"] unsignedIntegerValue];

        [manager getThumbWithId:id width:width height:height format:format quality:quality resultHandler:handler];

      }

进入getThumbWithId方法,

- (void)getThumbWithId:(NSString *)id width:(NSUInteger)width height:(NSUInteger)height format:(NSUInteger)format quality:(NSUInteger)quality resultHandler:(ResultHandler *)handler {
  PMAssetEntity *entity = [self getAssetEntity:id];
  if (entity && entity.phAsset) {
    PHAsset *asset = entity.phAsset;
    [self fetchThumb:asset width:width height:height format:format quality:quality resultHandler:handler];
  } else {
    [handler replyError:@"asset is not found"];
  }
}

原生实现获取置顶宽高缩略图方法实现:
使用iOS原生类PHImageManager

                     targetSize:CGSizeMake(width, height)
                    contentMode:PHImageContentModeAspectFill
                        options:options
                  resultHandler:^(UIImage *result, NSDictionary *info)

来获取缩略图。

- (void)fetchThumb:(PHAsset *)asset width:(NSUInteger)width height:(NSUInteger)height format:(NSUInteger)format quality:(NSUInteger)quality resultHandler:(ResultHandler *)handler {
  PHImageManager *manager = PHImageManager.defaultManager;
  PHImageRequestOptions *options = [PHImageRequestOptions new];
  [options setNetworkAccessAllowed:YES];
  [options setProgressHandler:^(double progress, NSError *error, BOOL *stop,
          NSDictionary *info) {
      if (progress == 1.0) {
        [self fetchThumb:asset width:width height:height format:format quality:quality resultHandler:handler];
      }
  }];
  [manager requestImageForAsset:asset
                     targetSize:CGSizeMake(width, height)
                    contentMode:PHImageContentModeAspectFill
                        options:options
                  resultHandler:^(UIImage *result, NSDictionary *info) {
                      BOOL downloadFinished = [PMManager isDownloadFinish:info];

                      if (!downloadFinished) {
                        return;
                      }

                      if ([handler isReplied]) {
                        return;
                      }
                      NSData *imageData;
                      if (format == 1) {
                        imageData = UIImagePNGRepresentation(result);
                      } else {
                        double qualityValue = (double) quality / 100.0;
                        imageData = UIImageJPEGRepresentation(result, qualityValue);
                      }

                      FlutterStandardTypedData *data = [FlutterStandardTypedData typedDataWithBytes:imageData];
                      [handler reply:data];
                  }];
}

相关文章

  • flutter图片内存优化

    方法一 按照给定尺寸进行图片的解码,而不是解码整个图片的尺寸,用来减少内存的占用。 官方文档:https://ap...

  • flutter 图片内存优化

    最近做项目时,有个朋友圈类似的界面,发现多张图片时,内存暴增了400M左右,debug发现可能是图片过多造成的,查...

  • Flutter优化相关

    Flutter之禅 内存优化篇Flutter ImageCacheFlutter 性能优化 Tips

  • 性能优化-整理中

    图片优化内存优化

  • Flutter相关优化

    性能优化 1、内存优化使用flutter performance等工具查看内存和帧率使用DevTools来gc查看...

  • Andorid性能优化之-图片优化

    图片优化 优化图片Bitmap资源的使用 & 内存管理 图片的内存占据了App的大部分 1.使用完毕后释放图片资源...

  • 内存优化

    一、android图片占用的内存和优化

  • 性能优化04-图片优化

    性能优化04-图片优化 一、图片压缩 图片在APP中通常占用很大的内存,所以经常需要进行图片压缩。 常用的图片压缩...

  • Android内存优化之图片内存优化

    本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一...

  • 内存优化:图片定位

    目标 通常最占内存的就是图片,内存优化最优先从图片入手,排查下大内存的图片有哪些,是哪里产生的,是不是合理 定位 ...

网友评论

    本文标题:flutter图片内存优化

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