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://www.haomeiwen.com/subject/kdrkcltx.html