Flutter模型加载插件dartlcemodel的使用

Flutter 模型加载插件 dartlcemodel 的使用

简介

DartLceModel 是一个用于 Dart 平台的反应式数据加载库,旨在加载数据并报告操作状态(Loading/Content/Error)。

特点

  • 使用广泛的设计模式,包含 Loading/Content/Error 状态。
  • 使用缓存作为“真理来源”,支持 CacheThenNetLceModel
  • 检查数据的有效性(如是否最新)。
  • 如果刷新失败,则回退到无效的缓存数据,允许离线应用使用。
  • 支持数据的刷新或更新以实现重新加载或服务器数据更新操作。
  • 缓存可以独立于加载进行失效处理,允许延迟数据更新和复杂数据关联。
  • 可扩展的架构。
  • 经过充分测试。

示例

该项目包含一个示例应用,该应用会:

  • 加载 GitHub 用户的仓库列表,并缓存结果数据。
  • 外部失效缓存,使活动监听器重新加载数据。

目录

  • 设置依赖
  • LceState
  • LceModel
  • CacheThenNetLceModel
  • 获取和缓存数据
  • 选择 EntityValidator
  • 显示无效数据和缓存回退
  • 缓存失效和数据更新
  • 按需缓存重新获取
  • 缓存服务实现
  • 在小部件中设置模型的完整示例
  • 获取仅数据流和流变换
  • 状态变换

设置依赖

$ dart pub add dartlcemodel

LceState

LceState 是一种现代的应用架构方法,建议将应用程序的组合状态打包到一个不可变的状态对象流中。每个对象应包含处理、转换和显示所需的所有数据集。除了数据本身之外,最常用的信息是数据加载管道的状态。

/// Loading 类型
enum LoadingType {
  /// 正在加载。可能是初始加载操作
  loading,
  /// 加载更多项目以供分页视图使用
  loadingMore,
  /// 刷新内容
  refreshing,
  /// 更新服务器上的数据
  updating
}

LceModel

LceState 在这个库中由简单的用例接口生成。

/// 基础 LCE 用例,具有 [state] 和 [refresh] 属性
/// [DATA] 被加载的数据类型
abstract class LceUseCase<DATA extends Object> {
    /// 模型状态。订阅开始数据加载。当最后一个订阅者取消时,模型取消内部组件的数据更新
    Stream<LceState<DATA>> get state;

    /// 请求刷新数据。数据将在异步中更新
    Future<void> refresh();
}

CacheThenNetLceModel

这种类型的模型首先尝试从缓存中获取数据,如果未找到或缓存数据已过期,则从网络加载数据。以下是使用此类型模型进行数据加载的序列图。

final useCase = LceModel.cacheThenNet(
    'params', // 参数标识要加载的数据
    serviceSet, // 一组缓存+网络服务
    startWith: const LceState.loading(null, false), // 可选初始状态,在订阅时发出
    logger: logger // 可选日志记录器以了解用例内部情况
);

获取和缓存数据

缓存模型使用两个服务从网络获取数据并在本地存储它。

  • NetService - 从网络加载数据。
  • CacheService - 将数据保存在本地。

选择 EntityValidator

以下是一些可用的验证器:

  • Simple - 一个初始化为有效状态的简单数据类。
  • Never - 从未有效的。
  • Always - 始终有效的。
  • Lifespan - 一个初始化为时间有效期值的验证器,到期后变为无效。

显示无效数据和缓存回退

当网络连接不可用时,你可以回退到缓存数据。如果没有可用的缓存数据,你只会得到 null 作为 data 属性的值。

缓存失效和数据更新

当某些事情发生在另一个部分时,复杂的应用程序可能需要刷新部分应用程序中的某些数据。例如,当收到推送通知时,刷新聊天应用的消息列表。使用反应式缓存服务,这种失效可以通过简单而干净的方式完成。

/// 全局可用的服务集
late ServiceSet<List<Repository>, String> serviceSet;

void main() {
  // 创建一组服务
  // - 数据的内存缓存
  // - 从服务器获取数据的服务。`isolated()` 在 [Isolate] 中运行网络请求和解析
  serviceSet = ServiceSet(
      CacheService<List<Repository>, String>.withSyncDelegate(MemoryCacheDelegate.map()),
      RepositoryNetService().isolated()
  );

  runApp(const MyApp());
}

// 后续在小部件中
final refresh = GestureDetector(
  onTap: () async {
    await serviceSet.cache.invalidateAll();
  },
  child: const Icon(
    Icons.refresh,
    size: 26.0,
  )
);

按需缓存重新获取

考虑一个具有复杂内部结构的缓存服务,该服务通过某种内部逻辑进行更新。例如,数据库保存实体并直接更新记录。在这种情况下,你需要某种方式来通知数据更改的订阅者。

/// 缓存服务有两个方法可以调用,使其重新获取数据并更新其活动客户端
class CacheService {
  Future<void> refetch(P params); // 完成
  Future<void> refetchAll(); // 完成
}

缓存服务实现

虽然你可以实现任何缓存服务,但库附带了一个简单的 AsyncDelegateCacheServiceSyncDelegateCacheService,它们使用以下异步/同步委托进行数据 I/O。

final cache = CacheService<SomeData, String>.withSyncDelegate(MemoryCacheDelegate.map());

在小部件中设置模型的完整示例

class LceWidget<D extends Object> extends StatefulWidget {
  final String params;

  const LceWidget({Key? key, required this.params}) : super(key: key);

  [@override](/user/override)
  State<LceWidget<D>> createState() => _LceWidgetState();
}

class _LceWidgetState<D extends Object> extends State<LceWidget<D>> {
  LceUseCase<D>? _useCase;
  StreamSubscription<LceState<D>>? _subscription;
  late LceState<D> _lceState;

  [@override](/user/override)
  void initState() {
    super.initState();
    _subscribe();
  }

  [@override](/user/override)
  void didUpdateWidget(LceWidget<D> oldWidget) {
    super.didUpdateWidget(oldWidget);
    // 检查是否需要加载另一组数据
    if (widget.params != oldWidget.params) {
      _unsubscribe();
      _subscribe();
    }
  }

  [@override](/user/override)
  void dispose() {
    super.dispose();
    _unsubscribe();
  }

  _subscribe() {
    // 初始状态以显示
    _lceState = const LceState.loading(null, false);
    _useCase = LceModel.cacheThenNet(
        widget.params, // 参数标识要加载的数据
        serviceSet // 一组缓存+网络服务 - 全局定义或通过 DI 提供
    );
    _subscription = _useCase!.state.listen((newLceState) {
      setState(() { _lceState = newLceState; });
    });
  }

  _unsubscribe() {
    _subscription?.cancel();
    _subscription = null;
    _useCase = null;
  }

  Future<void> _refresh() async {
    return _useCase?.refresh() ?? Future.value();
  }

  [@override](/user/override)
  Widget build(BuildContext context)  => lceState.when(
      loading: (_) => const LoadingState(), // 加载小部件
      content: (state) => ContentState(repositories: state.data), // 内容小部件
      error: (state) => ErrorState(error: state.error, onRetry: () async { await _refresh(); }) // 错误小部件
  );
}

更多关于Flutter模型加载插件dartlcemodel的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter模型加载插件dartlcemodel的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


dartlcemodel 是一个用于在 Flutter 应用中加载和管理机器学习模型的插件。它支持从本地或远程加载模型,并提供了一种简单的方式来使用这些模型进行推理。以下是如何使用 dartlcemodel 插件的基本步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 dartlcemodel 插件的依赖。

dependencies:
  flutter:
    sdk: flutter
  dartlcemodel: ^0.1.0  # 请使用最新的版本号

然后运行 flutter pub get 来安装依赖。

2. 加载模型

dartlcemodel 支持从本地文件或远程 URL 加载模型。以下是两种加载方式的示例:

从本地文件加载模型

import 'package:dartlcemodel/dartlcemodel.dart';

Future<void> loadModelFromFile() async {
  String modelPath = 'assets/model.tflite';
  Model model = await Model.fromFile(modelPath);
  print('Model loaded from file');
}

从远程 URL 加载模型

import 'package:dartlcemodel/dartlcemodel.dart';

Future<void> loadModelFromUrl() async {
  String modelUrl = 'https://example.com/path/to/model.tflite';
  Model model = await Model.fromUrl(modelUrl);
  print('Model loaded from URL');
}

3. 使用模型进行推理

加载模型后,你可以使用它来进行推理。以下是一个简单的示例:

import 'package:dartlcemodel/dartlcemodel.dart';

Future<void> runInference() async {
  String modelPath = 'assets/model.tflite';
  Model model = await Model.fromFile(modelPath);

  // 假设输入是一个包含 224x224 图像的 Float32List
  List<double> input = List.filled(224 * 224 * 3, 0.0);

  // 进行推理
  List<double> output = await model.run(input);

  print('Inference result: $output');
}

4. 处理输出

推理的结果通常是一个 List<double>,你可以根据具体的模型和应用场景来处理这些输出。

5. 清理资源

在使用完模型后,确保释放资源以避免内存泄漏。

void disposeModel(Model model) {
  model.dispose();
}

6. 错误处理

在使用 dartlcemodel 时,可能会遇到各种错误,例如模型加载失败或推理错误。确保在代码中适当地处理这些错误。

try {
  Model model = await Model.fromFile('assets/model.tflite');
} catch (e) {
  print('Failed to load model: $e');
}
回到顶部