在flutter web上缓存图像,是不是需要?

Posted

技术标签:

【中文标题】在flutter web上缓存图像,是不是需要?【英文标题】:Caching Image on flutter web, is it required?在flutter web上缓存图像,是否需要? 【发布时间】:2020-07-25 22:35:22 【问题描述】:

由于CachedNetworkImage 不能在flutter web 上工作,在移植时,我尝试使用它,但我的问题是我们真的需要这个吗?或者我们只使用 Image。网络和浏览器和服务工作者将处理缓存部分(然后由服务器的响应标头通过例如 cache-control="max-age=43200, public" 设置)

这用于我正在进行的送餐项目https://www.santaiyamcha.com

以下是我用来替换似乎效果不佳的 CachedNetworkImage 的类。

import 'package:flutter/material.dart';
import 'package:http/http.dart';

import 'package:http_extensions_cache/http_extensions_cache.dart';
import 'package:http_extensions/http_extensions.dart';

/// Builds a widget when the connectionState is none and waiting
typedef LoadingBuilder = Widget Function(BuildContext context);

/// Builds a if some error occurs
typedef ErrorBuilder = Widget Function(BuildContext context, Object error);

class MeetNetworkImage extends StatelessWidget 
  /// Image url that you want to show in your app.
  final String imageUrl;

  /// When image data loading from the [imageUrl],
  /// you can build specific widgets with [loadingBuilder]
  final LoadingBuilder loadingBuilder;

  /// When some error occurs,
  /// you can build specific error widget with [errorBuilder]
  final ErrorBuilder errorBuilder;

  final double scale;

  final double width;
  final double height;
  final Color color;

  final FilterQuality filterQuality;

  final BlendMode colorBlendMode;

  final BoxFit fit;
  final AlignmentGeometry alignment;

  final ImageRepeat repeat;

  final Rect centerSlice;
  final bool matchTextDirection;

  /// Whether to continue showing the old image (true), or briefly show nothing
  /// (false), when the image provider changes.
  final bool gaplessPlayback;

  final String semanticLabel;
  final bool excludeFromSemantics;

  MeetNetworkImage(
    @required this.imageUrl,
    this.loadingBuilder = null,
    this.errorBuilder = null,
    this.scale = 1.0,
    this.height,
    this.width,
    this.color = const Color(0xFDFFFF),
    this.fit = BoxFit.fill,
    this.alignment = Alignment.center,
    this.repeat = ImageRepeat.noRepeat,
    this.semanticLabel,
    this.centerSlice,
    this.colorBlendMode,
    this.excludeFromSemantics = false,
    this.filterQuality = FilterQuality.low,
    this.matchTextDirection = false,
    this.gaplessPlayback = false,
  )  : assert(imageUrl != null),
        assert(alignment != null),
        assert(repeat != null),
        assert(matchTextDirection != null);

  Future<Response> getUrlResponse() 
    /*
    //The caching part  I tried, does not seems working
    final client = ExtendedClient(
      inner: Client(),
      extensions: [
        CacheExtension(
          //logger: Logger("Cache"),
          defaultOptions: CacheOptions(
            expiry: const Duration(hours: 168),
            // The duration after the cached result of the request will be expired.
            //forceUpdate: false, // Forces to request a new value, even if an valid cache is available
            //forceCache: false, // Forces to return the cached value if available (even if expired).
            //ignoreCache: true, //Indicates whether the request should bypass all caching logic
            //returnCacheOnError: true, //If [true], on error, if a value is available in the  store if is returned as a successful response (even if expired).
            keyBuilder: (request) => "$request.method_$imageUrl.toString()",
            // Builds the unqie key used for indexing a request in cache.
            store: MemoryCacheStore(),
            // The store used for caching data.
            shouldBeSaved: (response) =>
                response.statusCode >= 200 && response.statusCode < 300,
          ),
        )
      ],
    );

    return client.get(imageUrl);
     */
    return get(imageUrl);
  

  Widget getLoadingWidget(BuildContext context) 
    if (loadingBuilder != null) 
      return loadingBuilder(context);
     else
      return Container(
          height: height, width: width,
          child: Center(
            child: CircularProgressIndicator()
          )
          /*Image.asset(
          'assets/img/loading4.gif',
          height: height,
          width: width,
          fit: BoxFit.contain,
        ),*/
          );
  

  Widget getErrorWidget(BuildContext context, String error) 
    if (errorBuilder != null) 
      return errorBuilder(context, error);
     else
      return Center(child: Icon(Icons.error));
  

  @override
  Widget build(BuildContext context) 
    return FutureBuilder(
      future: getUrlResponse(),
      builder: (BuildContext context, AsyncSnapshot<Response> snapshot) 
        switch (snapshot.connectionState) 
          case ConnectionState.none:
          case ConnectionState.waiting:
            return getLoadingWidget(context);
          case ConnectionState.active:
          case ConnectionState.done:
            if (snapshot.hasError)
              return getErrorWidget(context, snapshot.error);
            if (!snapshot.hasData)
              return getErrorWidget(context, snapshot.error);
            //return getLoadingWidget(context);
            return Image.memory(
              snapshot.data.bodyBytes,
              scale: scale,
              height: height,
              width: width,
              color: color,
              fit: fit,
              alignment: alignment,
              repeat: repeat,
              centerSlice: centerSlice,
              colorBlendMode: colorBlendMode,
              excludeFromSemantics: excludeFromSemantics,
              filterQuality: filterQuality,
              gaplessPlayback: gaplessPlayback,
              matchTextDirection: matchTextDirection,
              semanticLabel: semanticLabel,
            );
        
        return Container();
      ,
    );
  

你有什么建议?

【问题讨论】:

尚未确认 :( 但我开始注意到缓存有时会发生在浏览器和标头设置之间 【参考方案1】:

我正在使用FadeInImage.memoryNetwork。它工作正常。浏览器处理缓存部分。

【讨论】:

【参考方案2】:

没有。这是谷歌浏览器的一个问题,它更喜欢“缓存控制”而不是电子标签或上次修改的标题。就我而言,我使用的是基于电子标签缓存的 Firefox。事情就是这样。

如果你使用 setState(()) 或者 Flutter 引擎由于某种原因调用了 setState ,图像会被重建,如果图像没有被缓存,它会被重新获取。为防止出现这种情况,请使用标头 cache-control: max-age=&lt;any value greater than 0&gt;,它会在 Chrome 中正常工作。

或者只是使用网络渲染器 canvaskit 构建应用程序 - flutter build web --web-renderer canvaskit

我根据我的经验得出这个结论,但我在任何地方都找不到,希望对你有帮助:)

【讨论】:

您可以编辑您的答案以添加更多空格,使其更具可读性吗?如果可能的话,你能把代码放在代码块里吗?【参考方案3】:

如果您使用的是旧版本,请尝试更新您的 Flutter 版本,并从图像提供程序界面使用。

浏览器会处理剩下的事情 示例:

创建容器在装饰中添加装饰添加图片装饰 然后从内存或网络图像中添加。

【讨论】:

以上是关于在flutter web上缓存图像,是不是需要?的主要内容,如果未能解决你的问题,请参考以下文章

图像列表不显示在 Flutter-web 中

如何从 Flutter-web 中的小部件创建图像?

如何在 Flutter web 上显示资产图像?

如何在 Flutter Web 中显示 Firebase 存储图像。我有图片网址。显示 URL 而不是图像。但另一侧图像链接已完美完成

如何在 Flutter 中缓存来自 Firebase 的图像?

适用于 Web 和移动设备的 Flutter 图像选择器