Flutter离线优先数据同步插件brick_offline_first_with_supabase的使用

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

Flutter离线优先数据同步插件 brick_offline_first_with_supabase 的使用

brick_offline_first_with_supabase 是一个用于Flutter应用的离线优先数据同步插件,它简化了Supabase与OfflineFirstRepository的集成。本文将详细介绍如何使用该插件,并提供完整的示例代码。

Repository

配置仓库

首先,我们需要配置一个继承自OfflineFirstWithSupabaseRepository的仓库类。以下是一个示例:

import 'package:brick_offline_first_with_supabase/brick_offline_first_with_supabase.dart';
import 'package:brick_sqlite/brick_sqlite.dart';
import 'package:brick_sqlite/memory_cache_provider.dart';
import 'package:brick_supabase/brick_supabase.dart';
import 'package:sqflite/sqflite.dart' show databaseFactory;
import 'package:supabase/supabase.dart';

// 假设已经生成了 brick.g.dart 和 schema.g.dart 文件
import 'brick/brick.g.dart';
import 'brick/db/schema.g.dart';

class MyRepository extends OfflineFirstWithSupabaseRepository {
  static late MyRepository? _singleton;

  MyRepository._({
    required super.supabaseProvider,
    required super.sqliteProvider,
    required super.migrations,
    required super.offlineRequestQueue,
    super.memoryCacheProvider,
  });

  factory MyRepository() => _singleton!;

  static void configure({
    required String supabaseUrl,
    required String supabaseAnonKey,
  }) {
    // 创建客户端和队列
    final (client, queue) = OfflineFirstWithSupabaseRepository.clientQueue(
      databaseFactory: databaseFactory,
    );

    // 配置 Supabase 客户端
    final provider = SupabaseProvider(
      SupabaseClient(supabaseUrl, supabaseAnonKey, httpClient: client),
      modelDictionary: supabaseModelDictionary,
    );

    // 初始化仓库
    _singleton = MyRepository._(
      supabaseProvider: provider,
      sqliteProvider: SqliteProvider(
        'my_repository.sqlite',
        databaseFactory: databaseFactory,
        modelDictionary: sqliteModelDictionary,
      ),
      migrations: migrations,
      offlineRequestQueue: queue,
      memoryCacheProvider: MemoryCacheProvider(),
    );
  }
}

使用 supabase_flutter

如果你使用的是 supabase_flutter 包,可以在初始化时创建客户端和队列:

final (client, queue) = OfflineFirstWithSupabaseRepository.clientQueue(databaseFactory: databaseFactory);
await Supabase.initialize(url: supabaseUrl, anonKey: supabaseAnonKey, httpClient: client);
final supabaseProvider = SupabaseProvider(Supabase.instance.client, modelDictionary: ...);

离线队列注意事项

在某些情况下,你可能需要忽略特定路径的请求。例如,Supabase的Auth或Storage路径默认不会被缓存和重试:

final (client, queue) = OfflineFirstWithSupabaseRepository.clientQueue(
  databaseFactory: databaseFactory,
  ignorePaths: {},
);

// 如果你不希望重试某些函数并处理响应,可以添加如下路径:
final (client, queue) = OfflineFirstWithSupabaseRepository.clientQueue(
  databaseFactory: databaseFactory,
  ignorePaths: {
    '/auth/v1',
    '/storage/v1',
    '/functions/v1'
  },
);

注意:如果更改了ignorePaths的默认值,你需要维护这些路径以适应Supabase的更新。

实时数据同步

Brick支持通过Supabase实时事件自动更新数据。首先设置你的表来广播变更,然后在应用程序中监听这些变更:

// 监听所有变更
final customers = MyRepository().subscribeToRealtime<Customer>();

// 或者监听特定过滤条件的结果
final customers = MyRepository().subscribeToRealtime<Customer>(query: Query.where('id', 1));

// 使用流结果
final customersSubscription = customers.listen((value) {});

// 始终关闭你的流
await customersSubscription.cancel();

注意:实时数据同步可能会变得昂贵,请设计你的应用程序以适应适当的规模。对于更便宜的设备内反应性,可以使用.subscribe()

模型

@ConnectOfflineFirstWithSupabase

这个注解用于标记可以被一个或多个提供程序序列化的模型:

@ConnectOfflineFirstWithSupabase(
  supabaseConfig: SupabaseSerializable(),
  sqliteConfig: SqliteSerializable(),
)
class MyModel extends OfflineFirstWithSupabaseModel {}

关联和外键

字段类型为extends OfflineFirstWithSupabaseModel的类会自动被视为Supabase中的外键。只有当列名与字段名不同时,才需要指定列名:

class User extends OfflineFirstWithSupabaseModel {
  @Supabase(foreignKey: 'address_id')
  final Address address;

  @Sqlite(ignore: true)
  String get addressId => address.id;
}

class Address extends OfflineFirstWithSupabaseModel{
  final String id;
}

注意:如果关联是可空的(如Address?),则查询可能会返回数据库中的所有记录。在这种情况下,你可以使用Supabase的策略来解决这个问题。

示例Demo

以下是一个完整的示例,展示了如何使用brick_offline_first_with_supabase插件:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 配置仓库
  MyRepository.configure(
    supabaseUrl: 'YOUR_SUPABASE_URL',
    supabaseAnonKey: 'YOUR_SUPABASE_ANON_KEY',
  );

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

更多关于Flutter离线优先数据同步插件brick_offline_first_with_supabase的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter离线优先数据同步插件brick_offline_first_with_supabase的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个使用Flutter离线优先数据同步插件 brick_offline_first_with_supabase 的代码示例。这个插件允许你在Flutter应用中实现离线优先的数据同步,并且与Supabase进行集成。

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

dependencies:
  flutter:
    sdk: flutter
  brick_offline_first_with_supabase: ^latest_version  # 请替换为最新版本号
  supabase_flutter: ^latest_version  # 请替换为最新版本号

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

接下来,在你的 Flutter 应用中,你可以按照以下步骤来设置和使用 brick_offline_first_with_supabase 插件。

  1. 初始化 Supabase 客户端
import 'package:supabase_flutter/supabase_flutter.dart';

final SupabaseClient supabase = SupabaseClient(
  url: 'YOUR_SUPABASE_URL',
  anonKey: 'YOUR_ANON_KEY',
);
  1. 配置 brick_offline_first_with_supabase
import 'package:brick_offline_first_with_supabase/brick_offline_first_with_supabase.dart';

// 配置离线优先数据库
final OfflineDatabase offlineDatabase = OfflineDatabase(
  supabaseClient: supabase,
  tableName: 'your_table_name',  // 替换为你的表名
  localStorage: LocalStorage(),  // 使用默认的本地存储
);
  1. 创建数据模型
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:json_annotation/json_annotation.dart';

part 'your_model.g.dart';

@freezed
class YourModel with _$YourModel {
  const factory YourModel({
    required String id,
    required String name,
    // 其他字段
  }) = _YourModel;

  factory YourModel.fromJson(Map<String, dynamic> json) => _$YourModelFromJson(json);
  Map<String, dynamic> toJson() => _$YourModelToJson(this);
}

运行 flutter pub run build_runner build 来生成 your_model.g.dart 文件。

  1. 执行 CRUD 操作
void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 初始化离线数据库
  await offlineDatabase.initialize();

  runApp(MyApp());
}

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

class OfflineDemo extends StatefulWidget {
  @override
  _OfflineDemoState createState() => _OfflineDemoState();
}

class _OfflineDemoState extends State<OfflineDemo> {
  late OfflineDatabaseClient<YourModel> dbClient;

  @override
  void initState() {
    super.initState();
    dbClient = offlineDatabase.createClient<YourModel>(
      fromJson: (json) => YourModel.fromJson(json),
      toJson: (model) => model.toJson(),
    );
  }

  void addItem() async {
    final newItem = YourModel(id: Uuid().v4(), name: 'New Item');  // 使用 Uuid 生成唯一ID
    await dbClient.insert(newItem);
    // 同步到Supabase(可选,根据需求在合适时机调用)
    // await offlineDatabase.sync();
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ElevatedButton(
            onPressed: addItem,
            child: Text('Add Item'),
          ),
          // 显示数据列表(示例)
          Expanded(
            child: FutureBuilder<List<YourModel>>(
              future: dbClient.selectAll(),
              builder: (context, snapshot) {
                if (snapshot.connectionState == ConnectionState.done) {
                  final items = snapshot.data ?? [];
                  return ListView.builder(
                    itemCount: items.length,
                    itemBuilder: (context, index) {
                      return Text(items[index].name);
                    },
                  );
                } else {
                  return CircularProgressIndicator();
                }
              },
            ),
          ),
        ],
      ),
    );
  }
}

在上面的代码中,我们展示了如何初始化 brick_offline_first_with_supabase 插件,创建数据模型,并执行基本的 CRUD 操作。你可以根据需要扩展和修改这些代码,以适应你的具体应用场景。

请注意,这只是一个基本的示例,实际项目中可能需要处理更多的错误情况、同步策略等。此外,确保在实际部署前替换 YOUR_SUPABASE_URLYOUR_ANON_KEY 为你的 Supabase 项目的实际值。

回到顶部