Flutter离线优先与REST支持插件brick_offline_first_with_rest的使用

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

Flutter离线优先与REST支持插件brick_offline_first_with_rest的使用

OfflineFirstWithRestRepository 简化了与 OfflineFirstRepository 的 REST 集成。它包含一个串行队列,用于在单独的 SQLite 数据库中跟踪 REST 请求,只有在从主机收到响应后(即设备失去互联网连接)才会移除请求。参见 OfflineFirstWithRest#reattemptForStatusCodes

OfflineFirstWithRest 域使用与 OfflineFirst 相同的所有配置和注解。

模型

ConnectOfflineFirstWithRest

@ConnectOfflineFirstWithRest 装饰可以被一个或多个提供程序序列化的模型。离线优先在类级别上没有配置,仅扩展由其提供程序持有的配置:

@ConnectOfflineFirstWithRest(
  restConfig: RestSerializable(),
  sqliteConfig: SqliteSerializable(),
)
class MyModel extends OfflineFirstModel {}

从REST端点生成模型

提供了一个实用类,可使从JSON API生成模型变得简单。给定一个端点,转换器将推断字段类型并生成一个类。例如,以下内容会被保存到项目的 lib 目录中,并运行 dart lib/converter_script.dart

// lib/converter_script.dart
import 'package:brick_offline_first/rest_to_offline_first_converter.dart';

const BASE = "http://0.0.0.0:3000";
const endpoint = "$BASE/users";

final converter = RestToOfflineFirstConverter(endpoint: endpoint);

void main() {
  converter.saveToFile();
}

// => dart lib/converter_script.dart

在模型生成后,检查是否有 List<dynamic>null 类型。虽然转换器很聪明,但它并不比你更聪明。

测试

响应可以从 OfflineFirstWithRest 存储库中进行模拟。为方便起见,可以使用文件数据来模拟来自API的JSON响应:

// test/models/api/user.json
{
  "user": { "name" : "Thomas" }
}

// test/models/user_test.dart
import 'package:brick_sqlite/testing.dart';
import 'package:my_app/brick/repository.dart';

void main() {
  group("MySqliteProvider", () {
    late MyRepository repository;
    setUpAll(() async {
      repository = MyRepository(
        restProvider: RestProvider(
          client: StubOfflineFirstWithRest.fromFiles('http://0.0.0.0:3000', {
            'users': 'api/user.json'
          }).client,
        )
      );

      await repository.initialize()
    });
  });
}

默认情况下,对于 upsertget 方法,返回相同的响应,唯一的变化在于状态码。但是,可以为不同的方法配置响应:

StubOfflineFirstWithRest(
  baseEndpoint: 'http://0.0.0.0:3000',
  responses: [
    StubOfflineFirstRestResponse.fromFile('users', 'api/user.json', StubHttpMethod.get),
    StubOfflineFirstRestResponse.fromFile('users', 'api/user-post.json', StubHttpMethod.post),
  ],
)
不使用文件进行模拟

虽然将响应存储在文件中可以很方便且减少代码混乱,但也可以直接定义响应:

StubOfflineFirstWithRest(
  baseEndpoint: 'http://0.0.0.0:3000',
  responses: [
    StubOfflineFirstRestResponse('users', '{"name":"Bob"}'),
    StubOfflineFirstRestResponse('users', '{"name":"Alice"}'),
  ],
)
处理端点变化

端点的变化必须明确声明。例如,/user/users/users?by_first_name=Guy 都是不同的。实例化时,指定任何预期的变化:

StubOfflineFirstRestResponse<User>(
  endpoints: ["user", "users", "users?by_first_name=Guy"]
)
模拟多个模型

很少会只有一个模型需要模拟。可以高效地使用 StubOfflineFirstWithRest 对应用程序中的所有类进行模拟:

setUpAll() async {
  final config = {
    User: ['user', 'users'],
    // 即使是个别成员端点也必须声明以获取关联
    // REST 端点是手动配置的,所以内容可能会有所不同
    Hat: ['hat/1', 'hat/2', 'hats'],
  };
  final responses = config.entries.map((modelConfig) {
    return modelConfig.value.map((endpoint) {
      return StubOfflineFirstRestResponse.fromFile(
        'api/${modelConfig.key.toString().toLowerCase()}.json',
        endpoint: endpoint,
      );
    });
  }).expand((e) => e);
  final client = StubOfflineFirstWithRest(
    baseEndpoint: 'http://0.0.0.0:3000',
    responses: responses,
  ).client;
}

更多关于Flutter离线优先与REST支持插件brick_offline_first_with_rest的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter离线优先与REST支持插件brick_offline_first_with_rest的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用brick_offline_first_with_rest插件来实现离线优先与REST支持的一个基本示例。这个插件允许你的应用在没有网络连接时依然能够访问数据,并在网络恢复时同步数据。

首先,确保你已经在pubspec.yaml文件中添加了brick_offline_first_with_rest依赖:

dependencies:
  flutter:
    sdk: flutter
  brick_offline_first_with_rest: ^latest_version  # 替换为最新版本号

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

接下来,在你的Flutter项目中,你可以按照以下步骤配置和使用该插件:

  1. 初始化离线存储和REST客户端
import 'package:flutter/material.dart';
import 'package:brick_offline_first_with_rest/brick_offline_first_with_rest.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Offline First with REST Demo'),
        ),
        body: OfflineFirstDemo(),
      ),
    );
  }
}

class OfflineFirstDemo extends StatefulWidget {
  @override
  _OfflineFirstDemoState createState() => _OfflineFirstDemoState();
}

class _OfflineFirstDemoState extends State<OfflineFirstDemo> {
  late OfflineFirstDatabase _database;
  late OfflineFirstRestClient _client;

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

    // 初始化数据库(离线存储)
    _database = OfflineFirstDatabase.init(
      databaseName: 'my_database',
      tables: [
        OfflineFirstTable.init(
          tableName: 'items',
          columns: [
            OfflineFirstColumn.init('id', OfflineFirstColumnType.integer, isPrimaryKey: true, autoIncrement: true),
            OfflineFirstColumn.init('name', OfflineFirstColumnType.text),
            OfflineFirstColumn.init('value', OfflineFirstColumnType.integer),
          ],
        ),
      ],
    );

    // 初始化REST客户端
    _client = OfflineFirstRestClient.init(
      baseUrl: 'https://api.example.com',
      endpoints: [
        OfflineFirstEndpoint.init(
          endpointName: 'items',
          path: '/items',
          methods: [
            OfflineFirstHttpMethod.get,
            OfflineFirstHttpMethod.post,
            OfflineFirstHttpMethod.put,
            OfflineFirstHttpMethod.delete,
          ],
          table: 'items',
          mappers: {
            'get': (Map<String, dynamic> json) => Item.fromJson(json),
            'post': (Item item) => item.toJson(),
            'put': (Item item) => item.toJson(),
          },
        ),
      ],
      database: _database,
    );
  }

  @override
  Widget build(BuildContext context) {
    // 你的UI代码
    return Center(
      child: Text('离线优先与REST支持示例'),
    );
  }
}

class Item {
  int id;
  String name;
  int value;

  Item({required this.id, required this.name, required this.value});

  factory Item.fromJson(Map<String, dynamic> json) {
    return Item(
      id: json['id'] as int,
      name: json['name'] as String,
      value: json['value'] as int,
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'name': name,
      'value': value,
    };
  }
}
  1. 使用离线优先功能

一旦初始化完成,你可以使用_database_client来进行数据操作。例如,获取数据:

Future<List<Item>> fetchItems() async {
  List<Map<String, dynamic>> itemsJson = await _client.get('items');
  List<Item> items = itemsJson.map((json) => Item.fromJson(json)).toList();
  return items;
}

添加数据:

Future<void> addItem(Item item) async {
  await _client.post('items', item);
}

更新数据:

Future<void> updateItem(Item item) async {
  await _client.put('items', item);
}

删除数据:

Future<void> deleteItem(int id) async {
  await _client.delete('items', {'id': id});
}
  1. 同步数据

当网络恢复时,你可以手动或自动触发数据同步。通常,插件会处理大部分同步逻辑,但你可能需要监听网络状态变化来触发同步。

void syncData() async {
  await _client.syncAll();
}

请注意,上述代码是一个简化的示例,实际项目中你可能需要处理更多的错误情况、添加更多的UI组件以及根据具体需求进行自定义。此外,brick_offline_first_with_rest插件的具体API和用法可能会随着版本更新而变化,请参考最新的官方文档和示例代码。

回到顶部