Building Pixedge: A Wallpaper Feed That Stays Smooth With a Smart Image Pipeline

Aug 2026 · 2 min read

pixedge

I shipped Pixedge — a wallpaper app with the usual product shell: browse, like, download, set home/lock screen, premium limits, ads, remote config.

Users don’t judge wallpaper apps by architecture diagrams. They judge them by whether scrolling a dense grid stutters, and whether opening a detail view waits on a redundant re-download.

So the interesting work is SmartImageService.

The failure mode of naive image grids

Every tile wants a thumb. Every detail wants a full image. Without discipline you get:

  • duplicate downloads for the same URL
  • disk keys that collide or change across process restarts (hashCode is not a content key)
  • thumb re-encodes that burn CPU while the user is mid-scroll
  • full-image requests stuck behind a backlog of off-screen thumbnails

What the pipeline actually does

  1. Memory maps for thumb vs full paths, checked before any work.
  2. Stable disk keys — FNV-style hash of the URL plus length, so paths survive restarts and avoid Dart hashCode collisions.
  3. In-flight Future map — parallel tiles requesting the same URL share one Future.
  4. Priority queue — full images enqueue at the front; thumbs at the back. Max 4 concurrent processors.
  5. Thumb shortcut — if the cache-manager file is already under ~350KB, reuse it and skip a costly re-encode.
  6. Otherwise download via cache manager, compress with flutter_image_compress, write the stable path, complete waiters.

That is not glamorous. It is why the grid feels intentional on a mid-range Android device.

Setting a wallpaper is a system fight

WallpaperService serializes operations (_isOperationInProgress), validates the file, maps location to home/lock/both, and retries with backoff when the OEM wallpaper API flakes. Double-tap while a set is in flight gets a toast, not a race.

Local state for downloads/likes uses Isar. The backend companion (pixedge_backend) is a separate Laravel content plane — the mobile post should stay about the client pipeline unless you’re writing a CMS piece.

What I’d still harden

Eviction policy for the temp disk cache under storage pressure. Metrics on queue wait time vs decode time. And OEM wallpaper APIs will keep inventing new ways to fail — keep the retry budget explicit.

Bet: media apps are judged by cache discipline, not by the tile radius.

If you’re shipping image-heavy Flutter apps: prioritize the visible request, dedupe the invisible ones, and never use hashCode as a file name.


  • flutter
  • wallpaper
  • performance
  • caching
  • image-pipeline
  • mobile