Skip to content

FlyerImageMessage should set cacheWidth and cacheHeight #890

@tomquas

Description

@tomquas

While analyzing some ANR scenarios, i had this conversation this morning about image caches in flutter.
What's your take on this?

FlyerChatImageMessage seems to make correct assumptions about image size; does it set cacheHeight, too? should it?

Here's what the package actually does:

  Display constraints (from the package source):
  - BoxConstraints(maxHeight: 300) wraps the whole widget
  - Inside: AspectRatio(aspectRatio: message.width / message.height) +
  StackFit.expand
  - So display is: height ≤ 300px, width = height × aspectRatio

  Cache dimensions: the package calls Image(image: _imageProvider, fit:
  BoxFit.fill) — no cacheWidth/cacheHeight set anywhere, not even for its own
  remote image path. So full-resolution decode happens in all cases.

  For customImageProvider: since we pass a raw ImageProvider into Image(image:
  ..., fit: BoxFit.fill), wrapping it with ResizeImage is the only way to control
  decode dimensions.

  Should cacheHeight be set too? — Yes. The display height is bounded at 300
  (logical px). Given message.width and message.height are available on
  ImageMessage, we can compute the actual constrained dimensions precisely:

should we ask for a patch of FlyerChatImageMessage to set cacheHeight?

Yes, it's worth it. Here's the reasoning:

  The package already uses LayoutBuilder conditionally (only when topWidget !=
  null). A patch would:
  1. Make LayoutBuilder unconditional in _buildStack
  2. Pass constraints.maxWidth and constraints.maxHeight into Image(image:
  _imageProvider, cacheWidth: ..., cacheHeight: ...)

  This would benefit all callers — both the default CachedNetworkImageProvider
  path and any customImageProvider. The display dimensions are fully determined at
   that point (AspectRatio + BoxConstraints(maxHeight: 300)), so constraints in
  the LayoutBuilder already reflect the final pixel size.

  Without this patch, every image in every chat — including remote ones from the
  default path — is decoded at full resolution regardless of the 300px height cap.

  That said, ResizeImage on the customImageProvider side still makes sense as a
  local workaround in the meantime, since we control that code path. The patch
  just fixes the problem more broadly for all image types and all consumers of the
  package.

what about using topWidget?

Clever idea, but it doesn't help here. The constraints from LayoutBuilder are
  only passed to _buildStack when topWidget != null — but inside _buildStack,
  constraints is only used to size the topWidget overlay (line 343), not the Image
   itself. The Image(image: _imageProvider, fit: BoxFit.fill) ignores constraints
  entirely regardless.

  So passing a dummy topWidget would trigger LayoutBuilder but the constraints
  would never reach the Image decode call. That's exactly what makes the upstream
  patch necessary — the fix has to happen inside _buildStack where the Image is
  built.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions