AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Flutter Caching Data

skill-mdazadhossain95-flutter-agent-skills-flutter-caching-data · by mdazadhossain95

Implements caching strategies for Flutter apps to improve performance and offline support. Use when retaining app data locally to reduce network requests or speed up startup.

No reviews yet
0 installs
43 views
0.0% view→install

Install

$ agentstack add skill-mdazadhossain95-flutter-agent-skills-flutter-caching-data

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-mdazadhossain95-flutter-agent-skills-flutter-caching-data)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Flutter Caching Data? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Implementing Flutter Caching and Offline-First Architectures

Contents

  • [Selecting a Caching Strategy](#selecting-a-caching-strategy)
  • [Implementing Offline-First Data Synchronization](#implementing-offline-first-data-synchronization)
  • [Managing File System and SQLite Persistence](#managing-file-system-and-sqlite-persistence)
  • [Optimizing UI, Scroll, and Image Caching](#optimizing-ui-scroll-and-image-caching)
  • [Caching the FlutterEngine (Android)](#caching-the-flutterengine-android)
  • [Workflows](#workflows)

Selecting a Caching Strategy

Apply the appropriate caching mechanism based on the data lifecycle and size requirements.

  • If storing small, non-critical UI states or preferences: Use shared_preferences.
  • If storing large, structured datasets: Use on-device databases (SQLite via sqflite, Drift, Hive CE, or Isar).
  • If storing binary data or large media: Use file system caching via path_provider.
  • If retaining user session state (navigation, scroll positions): Implement Flutter's built-in state restoration to sync the Element tree with the engine.
  • If optimizing Android initialization: Pre-warm and cache the FlutterEngine.

Implementing Offline-First Data Synchronization

Design repositories as the single source of truth, combining local databases and remote API clients.

Read Operations (Stream Approach)

Yield local data immediately for fast UI rendering, then fetch remote data, update the local cache, and yield the fresh data.

Stream getUserProfile() async* {
  // 1. Yield local cache first
  final localProfile = await _databaseService.fetchUserProfile();
  if (localProfile != null) yield localProfile;

  // 2. Fetch remote, update cache, yield fresh data
  try {
    final remoteProfile = await _apiClientService.getUserProfile();
    await _databaseService.updateUserProfile(remoteProfile);
    yield remoteProfile;
  } catch (e) {
    // Handle network failure; UI already has local data
  }
}

Write Operations

Determine the write strategy based on data criticality:

  • If strict server synchronization is required (Online-only): Attempt the API call first. Only update the local database if the API call succeeds.
  • If offline availability is prioritized (Offline-first): Write to the local database immediately. Attempt the API call. If the API call fails, flag the local record for background synchronization.

Background Synchronization

Add a synchronized boolean flag to your data models. Run a periodic background task (e.g., via workmanager or a Timer) to push unsynchronized local changes to the server.

Managing File System and SQLite Persistence

File System Caching

Use path_provider to locate the correct directory.

  • Use getApplicationDocumentsDirectory() for persistent data.
  • Use getTemporaryDirectory() for cache data the OS can clear.
Future get _localFile async {
  final directory = await getApplicationDocumentsDirectory();
  return File('${directory.path}/cache.txt');
}

SQLite Persistence

Use sqflite for relational data caching. Always use whereArgs to prevent SQL injection.

Future updateCachedRecord(Record record) async {
  final db = await database;
  await db.update(
    'records',
    record.toMap(),
    where: 'id = ?',
    whereArgs: [record.id], // NEVER use string interpolation here
  );
}

Optimizing UI, Scroll, and Image Caching

Image Caching

Image I/O and decompression are expensive.

  • Use the cached_network_image package to handle file-system caching of remote images.
  • Custom ImageProviders: If implementing a custom ImageProvider, override createStream() and resolveStreamForKey() instead of the deprecated resolve() method.
  • Cache Sizing: The ImageCache.maxByteSize no longer automatically expands for large images. If loading images larger than the default cache size, manually increase ImageCache.maxByteSize or subclass ImageCache to implement custom eviction logic.

Scroll Caching

When configuring caching for scrollable widgets (ListView, GridView, Viewport), use the scrollCacheExtent property with a ScrollCacheExtent object. Do not use the deprecated cacheExtent and cacheExtentStyle properties.

// Correct implementation
ListView(
  scrollCacheExtent: const ScrollCacheExtent.pixels(500.0),
  children: // ...
)

Viewport(
  scrollCacheExtent: const ScrollCacheExtent.viewport(0.5),
  slivers: // ...
)

Widget Caching

  • Avoid overriding operator == on Widget objects. It causes O(N²) behavior during rebuilds.
  • Exception: You may override operator == only on leaf widgets (no children) where comparing properties is significantly faster than rebuilding, and the properties rarely change.
  • Prefer using const constructors to allow the framework to short-circuit rebuilds automatically.

Caching the FlutterEngine (Android)

To eliminate the non-trivial warm-up time of a FlutterEngine when adding Flutter to an existing Android app, pre-warm and cache the engine.

  1. Instantiate and pre-warm the engine in the Application class.
  2. Store it in the FlutterEngineCache.
  3. Retrieve it using withCachedEngine in the FlutterActivity or FlutterFragment.
// 1. Pre-warm in Application class
val flutterEngine = FlutterEngine(this)
flutterEngine.navigationChannel.setInitialRoute("/cached_route")
flutterEngine.dartExecutor.executeDartEntrypoint(DartEntrypoint.createDefault())

// 2. Cache the engine
FlutterEngineCache.getInstance().put("my_engine_id", flutterEngine)

// 3. Use in Activity/Fragment
startActivity(
  FlutterActivity.withCachedEngine("my_engine_id").build(this)
)

Note: You cannot set an initial route via the Activity/Fragment builder when using a cached engine. Set the initial route on the engine's navigation channel before executing the Dart entrypoint.

Workflows

Workflow: Implementing an Offline-First Repository

Follow these steps to implement a robust offline-first data layer.

  • [ ] Task Progress:
  • [ ] Define the data model with a synchronized boolean flag (default false).
  • [ ] Implement the local DatabaseService (SQLite/Hive) with CRUD operations.
  • [ ] Implement the remote ApiClientService for network requests.
  • [ ] Create the Repository class combining both services.
  • [ ] Implement the read method returning a Stream (yield local, fetch remote, update local, yield remote).
  • [ ] Implement the write method (write local, attempt remote, update synchronized flag).
  • [ ] Implement a background sync function to process records where synchronized == false.
  • [ ] Run validator -> review errors -> fix (Test offline behavior by disabling network).

Workflow: Pre-warming the Android FlutterEngine

Follow these steps to cache the FlutterEngine for seamless Android integration.

  • [ ] Task Progress:
  • [ ] Locate the Android Application class (create one if it doesn't exist and register in AndroidManifest.xml).
  • [ ] Instantiate a new FlutterEngine.
  • [ ] (Optional) Set the initial route via navigationChannel.setInitialRoute().
  • [ ] Execute the Dart entrypoint via dartExecutor.executeDartEntrypoint().
  • [ ] Store the engine in FlutterEngineCache.getInstance().put().
  • [ ] Update the target FlutterActivity or FlutterFragment to use .withCachedEngine("id").
  • [ ] Run validator -> review errors -> fix (Verify no blank screen appears during transition).

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.