Flutter高效数据加载与缓存插件simple_cached_future_builder的使用

Flutter高效数据加载与缓存插件simple_cached_future_builder的使用

特点

  • 简化过程:使用该类可以简化在数据获取后构建小部件的过程。在最基础的情况下,可以减少编写代码的行数。
  • 可选缓存:可以选择性地缓存获取的数据,从而减少在 build() 方法中调用的次数,尤其是在开发过程中频繁重建时。
  • 管理缓存:可以选择使用默认管理器或自定义类来管理缓存。可以轻松地与任何数据库包结合使用,以更永久地存储数据。

开始使用

simple_cached_future_builder 添加为 pubspec.yaml 文件中的依赖项。

基本用法

SimpleCachedFutureBuilder<String>(
    future: get(Uri.parse('https://www.boredapi.com/api/activity'))
            .then((value) => value.body),
    builder: (context, body) {
        return Text(jsonDecode(body)['activity']);
    },
)

相比 FutureBuilder,你不再需要在加载或出现错误时返回一个组件。你可以省去一些重复的代码(例如 if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) 的检查)。

FutureBuilder<String>(
    future: get(Uri.parse('https://www.boredapi.com/api/activity'))
        .then((value) => value.body),
    builder: ((context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
            return Text(jsonDecode(snapshot.data!)['activity']);
        } else {
            return Container();
        }
    }),
),

所有选项

SimpleCachedFutureBuilder<String>(
    future: get(Uri.parse('https://www.boredapi.com/api/activity'))
        .then((value) => value.body),
    builder: (context, activityResponse) {
        var activityData = jsonDecode(activityResponse);
        return Text(activityData['activity']);
    },
    onLoadingWidget: const CircularProgressIndicator(),
    onErrorWidget: (error) => const Icon(Icons.warning),
    cache: SimpleCache(
        tag: 'activitySuggestion',
        validFor: const Duration(minutes: 3)),
    cacheManager: MyCustomCacheManager(),
)
参数 示例 描述
future get(Uri.parse('https://www.boredapi.com/api/activity')) 必填:一个未来值。
builder builder: (context, activityResponse) => Text(activityResponse) 必填:一个从未来方法返回的数据中生成小部件的方法。必须返回一个组件。
onLoadingWidget onLoadingWidget: const CircularProgressIndicator() 可选:在加载期间显示的小部件。
onErrorWidget onErrorWidget: (error) => const Icon(Icons.warning) 可选:如果获取数据失败或值为 null 时显示的小部件。
cache SimpleCache(tag: 'activitySuggestion', validFor: const Duration(minutes: 3)) 可选:缓存值一段时间。
cacheManager BasicCacheManager() 可选:处理缓存的管理器,例如手动清除缓存或在会话之间缓存它。

自定义缓存管理器

可以覆盖缓存管理器以使用不同于默认管理器(BasicCacheManager())的方式来处理缓存。

class MyCustomCacheManager extends CacheManager {
  [@override](/user/override)
  void clearCache() {
    // TODO: 清除数据库
  }

  [@override](/user/override)
  Future<bool> exists(SimpleCache tag) async {
    // TODO: 检查值是否存在
  }

  [@override](/user/override)
  void removeCache(SimpleCache tag) {
    // TODO: 删除缓存
  }

  [@override](/user/override)
  retrieveCache(SimpleCache tag) {
    // TODO: 检索缓存
  }

  [@override](/user/override)
  void storeCache(SimpleCache tag, data) {
    // TODO: 存储缓存
  }
}

额外信息

注意,默认缓存管理器将数据存储在 Map 中。这意味着每次应用程序完全重启时,所有数据都会被清除。

此外,如果缓存大量不同的大数据量,这可能会导致内存使用率较高。

默认管理器适用于临时的小数据,这些数据不需要在不同会话之间保留。对于所有其他用途,建议使用自定义缓存管理器。有关使用 Hive 的示例实现,请参阅 example/lib/main.dart

完整示例代码

import 'dart:async';
import 'dart:convert';

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

/// 一个[Hive]数据库来存储缓存值
Box? database;

void main() async {
  await Hive.initFlutter();
  database = await Hive.openBox('database');
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'SimpleCachedFutureBuilder Example',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'SimpleCachedFutureBuilder Example'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  MyCustomCacheManager cacheManager = MyCustomCacheManager();

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          title: Text(widget.title),
          actions: [
            IconButton(
                tooltip: 'Clear all cache',
                onPressed: () {
                  cacheManager.clearCache();
                },
                icon: const Icon(Icons.clear_all))
          ],
        ),
        floatingActionButton: FloatingActionButton(
          tooltip: 'Reload',
          child: const Icon(Icons.refresh),
          onPressed: () => setState(() {}),
        ),
        body: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              futureBuilderForCache(SimpleCache(
                  tag: 'activitySuggestion',
                  // 允许在10秒后获取新数据
                  validFor: const Duration(seconds: 10))),
              futureBuilderForCache(
                  // 永远不获取新数据,保持第一次获取后的值
                  SimpleCache(tag: 'keepForEver')),
              // 总是获取新数据
              futureBuilderForCache(null),
            ],
          ),
        ));
  }

  SimpleCachedFutureBuilder futureBuilderForCache(SimpleCache? simpleCache) =>
      SimpleCachedFutureBuilder<String>(
        // 必填:一个未来值
        future: get(Uri.parse('https://www.boredapi.com/api/activity'))
            .then((value) => value.body),
        // 必填:一个从未来方法返回的数据中生成小部件的方法。必须返回一个组件
        builder: (context, activityResponse) {
          var activityData = jsonDecode(activityResponse);
          return Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              Text(activityData['activity']),
              if (simpleCache != null) cacheInfoWidget(simpleCache)
            ],
          );
        },
        // 可选:在数据获取期间显示的小部件
        onLoadingWidget: const CircularProgressIndicator(),
        // 可选:如果获取数据失败或值为 `null` 时显示的小部件
        onErrorWidget: (error) => const Icon(Icons.warning),
        // 可选:缓存值一段时间
        cache: simpleCache,
        // 可选:处理缓存的管理器,例如手动清除缓存或在会话之间缓存它
        cacheManager: cacheManager,
      );

  /// 显示剩余时间并添加一个特定缓存项的删除按钮
  Widget cacheInfoWidget(SimpleCache simpleCache) {
    return Padding(
      padding: const EdgeInsets.only(left: 8.0),
      child: StreamBuilder<Duration?>(
        stream: cacheManager.stream(simpleCache),
        builder: (context, snapshot) {
          return Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              Text(
                snapshot.data?.inSeconds != null
                    ? '${snapshot.data!.inSeconds} s'
                    : '   ',
                style: Theme.of(context).textTheme.labelSmall,
              ),
              IconButton(
                  tooltip: 'Delete this cache',
                  onPressed: (snapshot.data?.inSeconds ?? 0) > 0
                      ? () {
                          cacheManager.removeCache(simpleCache);
                        }
                      : null,
                  icon: const Icon(Icons.delete))
            ],
          );
        },
      ),
    );
  }
}

/// 使用Hive的一个自定义缓存管理器的示例实现。
class MyCustomCacheManager extends CacheManager<String> {
  [@override](/user/override)
  void clearCache() {
    super.clearCache();
    database?.clear();
  }

  [@override](/user/override)
  Future<bool> exists(SimpleCache tag) async {
    var exists = database?.containsKey(tag.tag) ?? false;
    return exists;
  }

  [@override](/user/override)
  void removeCache(SimpleCache tag) {
    super.removeCache(tag);
    database?.delete(tag.tag);
  }

  [@override](/user/override)
  String retrieveCache(SimpleCache tag) {
    return database?.get(tag.tag, defaultValue: '');
  }

  [@override](/user/override)
  void storeCache(SimpleCache tag, String data) {
    database?.put(tag.tag, data);
  }
}

更多关于Flutter高效数据加载与缓存插件simple_cached_future_builder的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter高效数据加载与缓存插件simple_cached_future_builder的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter应用中使用simple_cached_future_builder插件来实现高效数据加载与缓存的示例代码。这个插件能够帮助你缓存Future的结果,避免不必要的网络请求,从而提升应用的性能。

首先,你需要在你的pubspec.yaml文件中添加simple_cached_future_builder依赖:

dependencies:
  flutter:
    sdk: flutter
  simple_cached_future_builder: ^x.y.z # 请替换为最新版本号

然后运行flutter pub get来获取依赖。

接下来,在你的Flutter项目中,你可以按照以下步骤使用SimpleCachedFutureBuilder

  1. 定义一个Future函数来获取数据
import 'dart:convert';
import 'package:http/http.dart' as http;

Future<Map<String, dynamic>> fetchData() async {
  final response = await http.get(Uri.parse('https://api.example.com/data'));

  if (response.statusCode == 200) {
    return jsonDecode(response.body);
  } else {
    throw Exception('Failed to load data');
  }
}
  1. 使用SimpleCachedFutureBuilder来加载和缓存数据
import 'package:flutter/material.dart';
import 'package:simple_cached_future_builder/simple_cached_future_builder.dart';
import 'data_fetcher.dart'; // 假设上面的fetchData函数在这个文件中

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DataScreen(),
    );
  }
}

class DataScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Data Loader with Caching'),
      ),
      body: SimpleCachedFutureBuilder<Map<String, dynamic>>(
        future: fetchData(), // 调用你的数据获取函数
        cacheDuration: const Duration(minutes: 10), // 设置缓存持续时间
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Center(child: CircularProgressIndicator());
          } else if (snapshot.hasError) {
            return Center(child: Text('Error: ${snapshot.error}'));
          } else {
            final data = snapshot.data!;
            return ListView.builder(
              itemCount: data['items']?.length ?? 0,
              itemBuilder: (context, index) {
                final item = data['items']![index];
                return ListTile(
                  title: Text(item['title']),
                  subtitle: Text(item['description']),
                );
              },
            );
          }
        },
      ),
    );
  }
}

在这个示例中:

  • fetchData函数是一个异步函数,用于从网络获取数据。
  • SimpleCachedFutureBuilder用于加载和缓存数据。future参数是你想要缓存的Future,cacheDuration参数是你希望数据被缓存的时间。
  • builder参数是一个函数,用于构建UI。它接收一个snapshot对象,该对象包含连接状态和数据。如果数据正在加载,你可以显示一个加载指示器;如果加载出错,你可以显示错误信息;如果数据已经加载完成,你可以使用数据来构建你的UI。

通过这种方式,simple_cached_future_builder插件可以帮助你简化数据加载和缓存的逻辑,提高应用的性能和用户体验。

回到顶部