A simple way to cache values that result from rather expensive operations.

Overview

cached_value

Pub

A simple way to cache values that result from rather expensive operations.

It is useful to cache values that:

  • Are computed from other values in a consistent way;
  • Can be changed given known and unknown conditions;
  • Should not be computed on every access (like a getter);

Installation

Add to pubspec.yaml:

    dependencies:
       cached_value: <most recent version>

Find the most recent version on pub.

Usage

There are to types of cache to choose: simple and dependent.

Simple cache

A simple cache is only invalidated manually.

  int factorial(int n) {
    if (n < 0) throw ('Negative numbers are not allowed.');
    return n <= 1 ? 1 : n * factorial(n - 1);
  }

  int originalValue = 1;
  // One can also use CachedValue.simple
  final factorialCache = CachedValue(() => factorial(originalValue));
  print(factorialCache.value); // 1

  originalValue = 6;

  print(factorialCache.value); // 1
  print(factorialCache.isValid) // true, invalid only when invalidate is called
  
  // mark as invalid
  factorialCache.invalidate();
  print(factorialCache.isValid); // false

  print(factorialCache.value); // 720
  print(factorialCache.isValid); // true

It can be refreshed manually via the refresh method:

  // ...
  originalValue = 12;
  factorialCache.refresh();

  print(factorialCache.value); // 12

Dependent cache

A dependent cache is marked as invalid if its dependency value has changed.

  int factorial(int n) {
    if (n < 0) throw ('Negative numbers are not allowed.');
    return n <= 1 ? 1 : n * factorial(n - 1);
  }
  
  int originalValue = 1;
  final factorialCache = CachedValue.dependent(
    on: () => originalValue,
    compute: () => factorial(originalValue),
  );
  print(factorialCache.value); // 1
  print(factorialCache.isValid); // true
  
  // update value
  originalValue = 6;
  print(factorialCache.isValid); // false

  print(factorialCache.value); // 720
  print(factorialCache.isValid); // true

The dependency callback on is called on every value access. So it is recommended to keep it as declarative as possible.

// Avoid this:
final someCache = CachedValue.dependent(
  on: () => someExpensiveOperation(originalValue),
  compute: () => someCacheComputation(originalValue),
);

More docs

There is more detailed docs on the API documentation.

Motivation

Some imperative APIs such as the canvas paint on Flutter render objects of Flame's components may benefit from values that can be stored and reused between more than a single frame (or paint).

In some very specific cases, I found very convenient to store some objects across frames, like Paint and TextPainter instances.

Example on a render object:

class BlurredRenderObject extends RenderObject {

  // ...

  double _blurSigma = 0.0;
  double get blurSigma => _blurSigma;
  set blurSigma(double value) {
    _blurSigma = blurSigma;
    markNeedsPaint();
  }

  // ...

  @override
  void paint(PaintingContext context, Offset offset) {
    final canvas = context.canvas;


    final paint = Paint()..maskFilter = MaskFilter.blur(
        BlurStyle.normal, blurSigma
    );
    canvas.drawRect(Rect.fromLTWH(0, 0, 100, 100), paint);
  }
}

Can be changed to:

class BlurredRenderObject extends RenderObject {

  // ...

  double _blurSigma = 0.0;
  double get blurSigma => _blurSigma;
  set blurSigma(double value) {
    _blurSigma = blurSigma;
    markNeedsPaint();
  }

  // Add cache:
  late final paintCache = CachedValue.dependent(
    on: () => blurSigma,
    compute: () =>
        Paint()..maskFilter = MaskFilter.blur(BlurStyle.normal, blurSigma),
  );

  // ...

  @override
  void paint(PaintingContext context, Offset offset) {
    final canvas = context.canvas;

    // use cache:
    final paint = paintCache.value;
    canvas.drawRect(Rect.fromLTWH(0, 0, 100, 100), paint);
  }
}
You might also like...

Flutter Version Management: A simple CLI to manage Flutter SDK versions.

Flutter Version Management: A simple CLI to manage Flutter SDK versions.

fvm Flutter Version Management: A simple cli to manage Flutter SDK versions. FVM helps with the need for a consistent app builds by allowing to refere

Jan 8, 2023

Simple & Beautiful Note taking app written in dart with flutter UI toolkit.

Simple & Beautiful Note taking app written in dart with flutter UI toolkit.

Notes is a privacy oriented, Secure ,beautiful and fast application made in flutter, it supports various features like adding and saving notes. Hiding

Dec 30, 2022

A simple flexible API wrapper for coinbase commerce API. Totally unofficial.

coinbase_commerce A dart library that connects to interact with the Coinbase Commerce API. Enables projects to connect seamlessly to coinbase and rece

Oct 17, 2021

A few handy Flutter tools, dead simple `UriRouter` for `Uri`-based navigator or `BuildTracker` to track widget rebuilds and what caused them to rebuild.

noob A few handy tools for Flutter apps. UriRouter Hooks Providers PointerIndicator BuildTracker PeriodicListenable UriRouter Dead simple Uri-based pa

Jan 18, 2022

Simple generative arts created using Flutter

Simple generative arts created using Flutter

Flutter Generative Art Try it out on DartPad Simple Generative Art created using Flutter. Watch the full video on YouTube to know how to build it from

Aug 11, 2022

A simple Flutter / Dart Utility class for converting complex objects to uri and query string

A simple Flutter / Dart Utility class for converting complex or nested objects to uri and query strings you can follow the the article on how this cla

Sep 7, 2022

Simple CLI tool to produce icons for your next app.

icon_set_generator Simple CLI tool to enable easy production of icon sets for your next application. Installation Clone the repo and add bin/icon_set_

Nov 17, 2021

Provides simple conversion between Dart classes and Protobuf / Fixnum classes used in gRPC.

grpc_protobuf_convert Provides simple conversion between Dart classes and Protobuf / Fixnum classes used in gRPC. Using the library Add the repo to yo

Nov 1, 2022
Comments
  • Add ttl, update docs and move to declarative API

    Add ttl, update docs and move to declarative API

    Move to an API that allows composability:

    Simple:

    // this is unchanged, not a shorthand anymore, the default:
    CachedValue(() => factorial(originalValue));
    
    // from:
    CachedValue.simple(() => factorial(originalValue));
    
    // to:
    CachedValue(() => factorial(originalValue));
    

    Dependent:

    // from:
    final factorialCache = CachedValue.dependent(
      on: () => originalValue,
      compute: () => factorial(originalValue),
    );
    
    // to:
    final factorialCache = CachedValue(
      () => factorial(originalValue),
    ).withDependency(() => originalValue);
    
    
    opened by renancaraujo 0
  • [Request] Add large cache option

    [Request] Add large cache option

    So I really like where this package is going.

    Something I'd like to see is to have dependant cache hold multiple values.

    I'd like to build a cache of multiple values, and only compute if that value is new.

    For example

    string getName(int id) {
        switch(id) {
            case 0: 
                return "zero";
           case 1:
                return "one";
          ....
        }
    } 
    
    ... 
    int id = 0;
    final factorialCacheFirst = CachedValue.dependent(
        on: () => id,
        compute: () => getName(id),
      ); // computes
    
    final factorialCacheSecond = CachedValue.dependent(
        on: () => id,
        compute: () => getName(id),
      ); // returns cached value
    
    id = 1;
    final factorialCacheThird = CachedValue.dependent(
        on: () => id,
        compute: () => getName(id),
      ); // computes
    
    id = 0;
    final factorialCacheSecond = CachedValue.dependent(
        on: () => id,
        compute: () => getName(id),
      ); // returns cached value
    
    id = 1;
    final factorialCacheThird = CachedValue.dependent(
        on: () => id,
        compute: () => getName(id),
      ); // computes
    

    The summary is I'd love to cache a function's return value for a variety of inputs.

    opened by cadaniel 1
Owner
Renan
I do some cool stuff sometimes, some weird stuff all the time.
Renan
Utility to process H264 profile-level-id values

h264_profile_level_id Dart utility to process H264 profile-level-id values based on Google's libwebrtc C++ code. API import 'package:h264_profile_leve

Ibragim Abbasov 2 Apr 22, 2022
Simply extract required values from specific paths in a Map or a List

extract values from Map/List using dot-seprated strings you don't have to cast multiple times to fetch a simple values, this is very useful while working with i.e json data

Mohammed Al Ashaal 5 Nov 18, 2022
Flutter library that handles BLE operations for multiple devices

Flutter reactive BLE library Flutter library that handles BLE operations for multiple devices. Usage The reactive BLE lib supports the following: BLE

null 1 Apr 12, 2022
Cache json map to local file with Dart:io. Read file with sync api.

local_cache_sync 一个非常简单易用的Flutter本地储存库,适用于在本地储存一列轻量数据(例如用户保存在本地的设备信息,或者缓存一系列用户信息)。 local_cache_sync的所有方法都是同步,而不是异步的。这意味着你不需要使用await就可以获取数据。在flutter中,这

null 16 Jun 24, 2022
A better/safer way to handle environment variables in Flutter.

Envify A better and probably safer way to handle environment variables in Flutter. To read why this is better/safer in details, skip to the motivation

Frenco 96 Nov 5, 2022
A repo of dart packages that I've built along the way.

Pub-Dev This project is a mono-repo (of sorts) for the packages I've created along the way. Most of them were born for my own needs, some may be just

Gio Palacino 3 Jul 20, 2022
You can use this package for transition between screens with interesting way with amazing animation

You can use this package for transition between screens with interesting way with amazing animation

Sajad Rahimi 5 Jul 10, 2022
Simple GEL converter to showcase Flutter basics. Fundamental widgets and simple methods.

gel_converter A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if

Tornike Gogberashvili 1 Oct 17, 2021
A simple command-line application to generate simple folder and file structure for Flutter Applications

Kanza_cli is a simple command line tool to generate folder and file structure for your Flutter apps. To use it, you should do the followings: 1. First

Kanan Yusubov 9 Dec 16, 2022
Args simple - A simple argument parser and handler, integrated with JSON and dart

args_simple A simple argument parser and handler, integrated with JSON and dart:

Graciliano Monteiro Passos 1 Jan 22, 2022