Flutter资源缓存插件cached_resource的使用

发布于 1周前 作者 itying888 来自 Flutter

Flutter资源缓存插件cached_resource的使用

概述

cached_resource 是一个基于 NetworkBoundResource 方法实现的缓存插件,遵循单一数据源原则。它允许你定义一个缓存资源,在多个地方订阅更新,并确保只有一个网络请求会被调用,所有监听者都会接收到新的值。

使用步骤

1. 添加依赖

在你的 pubspec.yaml 文件中添加 cached_resource 作为依赖:

dependencies:
  cached_resource: ^latest_version

2. 资源存储配置

默认情况下,该插件只提供了内存存储(In-Memory Storage)。如果需要持久化存储或安全存储,你需要添加额外的依赖包:

3. 配置插件

在应用启动前,调用 ResourceConfig.setup 来配置存储工厂和日志记录器:

void main() {
  // Configuration for cached_resource.
  ResourceConfig.setup(
    persistentStorageFactory: const HiveResourceStorageProvider(),
    secureStorageFactory: const FlutterSecureResourceStorageProvider(),
    logger: CustomLogger(), // 可选
  );

  runApp(const MyApp());
}

定义资源/仓库

根据使用的存储类型,你可以以多种方式创建资源。

内存缓存示例

class AccountBalanceRepository extends CachedResource<String, AccountBalance> {
  AccountBalanceRepository(AccountBalanceApi api)
      : super.inMemory(
          'account_balance',
          fetch: api.getAccountBalance,
          cacheDuration: const CacheDuration(minutes: 15),
        );
}

持久化缓存示例

class CategoryRepository {
  CategoryRepository(CategoryApi api)
      : _categoryResource = CachedResource.persistent(
          'categories',
          fetch: (_) => api.getCategories(),
          cacheDuration: const CacheDuration(days: 15),
          decode: Category.listFromJson,
        );

  final CachedResource<String, List<Category>> _categoryResource;

  final _key = 'key';

  Stream<Resource<List<Category>>> watchCategories() =>
      _categoryResource.asStream(_key);

  Future<void> removeCategoryFromCache(String categoryId) {
    return _categoryResource.updateCachedValue(
      _key,
      (categories) => categories?.where((category) => category.id != categoryId).toList(),
    );
  }

  Future<void> invalidate() => _categoryResource.invalidate(_key);
}

安全缓存示例

class ProductSecretCodeRepository extends CachedResource<String, String> {
  ProductSecretCodeRepository(ProductApi api)
      : super.secure(
          'secret_code',
          fetch: api.getProductSecretCode,
          cacheDuration: const CacheDuration.newerStale(),
        );
}

自定义资源存储

你可以通过扩展 ResourceStorage 来创建自定义存储:

class UserRepository extends CachedResource<String, User> {
  UserRepository(UserApi api)
      : super(
          'users',
          fetch: api.getUserById,
          cacheDuration: const CacheDuration(days: 15),
          storage: YourCustomStorage(),
        );
}

监听资源流或获取值

获取单个值

void foo() async {
  final resource = await resource.get(productId);
  if (resource.hasData) {
    final product = resource.data!;
    // 处理产品数据
  } else if (resource.isError) {
    final error = resource.error;
    final Product? productFromCache = resource.data;
    // 显示错误或使用缓存数据
  }
}

监听资源更新

void startListening() async {
   _subscription = _categoryRepository.watchCategories().listen((resource) {
      if (resource.hasData) {
         final categories = resource.data!;
         // 显示类别
      } else if (resource.isError) {
         final error = resource.error!;
         final cachedCategories = resource.data;
         // 处理错误
      } else /*if (resource.isLoading)*/ { 
         // 显示加载状态
      }
   });
}

示例 Demo

以下是一个完整的示例应用,展示了如何使用 cached_resource 插件来管理产品列表及其详细信息页面:

import 'package:flutter/material.dart';
import 'package:cached_resource/cached_resource.dart';
import 'package:resource_storage_hive/resource_storage_hive.dart';
import 'package:resource_storage_secure/resource_storage_secure.dart';

void main() {
  ResourceConfig.setup(
    persistentStorageFactory: const HiveResourceStorageProvider(),
    secureStorageFactory: const FlutterSecureResourceStorageProvider(),
  );

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Cached Resource Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ProductListPage(),
    );
  }
}

class ProductListPage extends StatefulWidget {
  @override
  _ProductListPageState createState() => _ProductListPageState();
}

class _ProductListPageState extends State<ProductListPage> {
  late final ProductRepository _repository;

  @override
  void initState() {
    super.initState();
    _repository = ProductRepository(ProductApi());
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Products'),
      ),
      body: StreamBuilder<Resource<List<Product>>>(
        stream: _repository.watchProducts(),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            final resource = snapshot.data!;
            if (resource.hasData) {
              return ListView.builder(
                itemCount: resource.data!.length,
                itemBuilder: (context, index) {
                  final product = resource.data![index];
                  return ListTile(
                    title: Text(product.title),
                    onTap: () {
                      Navigator.push(
                        context,
                        MaterialPageRoute(
                          builder: (context) => ProductDetailsPage(product: product),
                        ),
                      );
                    },
                  );
                },
              );
            } else if (resource.isError) {
              return Center(child: Text('Error loading products'));
            } else {
              return Center(child: CircularProgressIndicator());
            }
          } else {
            return Center(child: CircularProgressIndicator());
          }
        },
      ),
    );
  }
}

class ProductDetailsPage extends StatelessWidget {
  final Product product;

  ProductDetailsPage({required this.product});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(product.title),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Text(product.description),
      ),
    );
  }
}

这个示例展示了如何使用 cached_resource 插件来管理和显示产品列表,并在点击时导航到产品的详细信息页面。希望这些内容能帮助你更好地理解和使用 cached_resource 插件。


更多关于Flutter资源缓存插件cached_resource的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter资源缓存插件cached_resource的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用cached_resource插件来进行资源缓存的示例代码。cached_resource插件允许你缓存网络资源,例如图片、JSON数据等,以提高应用的性能和用户体验。

1. 添加依赖

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

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

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

2. 初始化插件

在你的应用入口文件(通常是main.dart)中,初始化CachedResource插件:

import 'package:flutter/material.dart';
import 'package:cached_resource/cached_resource.dart';

void main() {
  // 初始化CachedResource
  CachedResource.init(
    baseCacheDir: (await getApplicationDocumentsDirectory()).path,
    logger: (message) {
      // 你可以在这里实现日志记录,例如使用print函数
      print(message);
    },
  );

  runApp(MyApp());
}

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

3. 使用CachedResource加载和缓存资源

以下是一个示例,展示了如何加载和缓存图片资源:

import 'package:flutter/material.dart';
import 'package:cached_resource/cached_resource.dart';
import 'dart:async';

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  CachedImage? _cachedImage;
  bool _loading = true;
  String? _error;

  @override
  void initState() {
    super.initState();

    // 加载并缓存图片
    loadCachedImage();
  }

  Future<void> loadCachedImage() async {
    setState(() {
      _loading = true;
      _error = null;
    });

    try {
      _cachedImage = await CachedResource.imageFromUrl(
        url: 'https://example.com/path/to/your/image.jpg',
        key: 'unique_image_key',  // 你可以使用任何唯一的键来标识这个资源
      );
    } catch (e) {
      setState(() {
        _error = e.toString();
        _loading = false;
      });
    } finally {
      if (_cachedImage != null) {
        setState(() {
          _loading = false;
        });
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Cached Resource Example'),
      ),
      body: Center(
        child: _loading
            ? CircularProgressIndicator()
            : _error != null
                ? Text('Error: $_error')
                : Image.file(_cachedImage!.file),
      ),
    );
  }
}

4. 清理缓存(可选)

如果你需要清理缓存,可以调用CachedResource.clearCache()方法:

void clearCache() async {
  await CachedResource.clearCache();
  print('Cache cleared');
}

你可以将这个方法绑定到一个按钮点击事件,以便用户手动清理缓存。

总结

以上示例展示了如何在Flutter应用中使用cached_resource插件来加载和缓存网络资源。这可以显著提高应用的性能,尤其是在需要频繁加载网络图片或数据的情况下。你可以根据实际需求对代码进行扩展和修改。

回到顶部