Flutter数据同步与后端服务插件deta的使用

Flutter数据同步与后端服务插件deta的使用

Deta

codecov style: very_good_analysis pub package License: MIT


一个用于与免费版Deta平台的HTTP API进行交互的Dart包。

警告

此客户端仅应在服务器端使用。


索引

开始使用

查看完整的示例 在这里

安装

pubspec.yaml 中添加依赖:

dependencies:
    deta: <version>

使用

我们声明一个类 Deta,它接收我们的私有凭证作为参数。client 参数可以接收两种不同的实现 DioClientDetaApiHttpClientDetaApi,你需要根据你的偏好选择并添加相应的依赖项。

final deta = Deta(projectKey: 'projectKey', client: DioClientDetaApi(dio: Dio()));

警告

你的 projectKey 是保密的,只能由你使用。任何人拥有你的项目密钥都可以访问你的数据库。请勿分享或将其提交到代码中。

DetaBase

DetaBase 是一个完全托管的、快速、可扩展且安全的NoSQL数据库,专注于最终用户的简洁性。

我们定义我们的 DetaBase,通过 base 方法接收数据库名称作为参数。如果数据库不存在,将在首次使用时自动创建。你可以创建任意数量的 DetaBase

一个 DetaBase 实例是一个数据集合,类似于键值存储、MongoDB集合或PostgreSQL/MySQL表。

final detabase = deta.base('lenguages');

方法

put

保存一个条目。如果键已存在,将更新该条目。

await detabase.put({
  'key': 'dart-g',
  'name': 'Dart',
  'description':
      'Dart is a general-purpose programming language that adds strong '
          'support for modularity, co-variant return types, and a strong '
          'emphasis on type safety.',
  'creator': 'Google',
  'year': 2012,
});
putMany

保存一个元素列表,该列表最多只能包含20个元素。

await detabase.putMany(
  items: lenguages.map((lenguage) => lenguage.toJson()).toList(),
);
insert

保存一个元素,类似于 put,但如果有此元素存在于 DetaBase 中,则会抛出 DetaObjectException。需要保存的元素必须包含 key

await detabase.insert({
  'key': 'r-f',
  'name': 'R',
  'description': 'R is a programming language and software environment '
      'for statistical computing and graphics.',
  'creator': 'R Foundation',
  'year': 1995,
});
update

从提供的 key 更新元素,需要传递整个元素,包括更新和未更改的部分。

await detabase.update(
  key: 'ruby-ym',
  item: <String, dynamic>{
    'key': 'ruby-ym',
    'name': 'Ruby',
    'description': 'Ruby is a dynamic, open source, general-purpose '
        'programming language with a focus on simplicity and productivity.',
    'creator': 'Yukihiro Matsumoto',
    'year': 1995,
  },
);
get

从键获取特定元素。

final item = await detabase.get('dart-g');
delete

从键删除特定元素。

final wasDeleted = await detabase.delete('ruby');
fetch

如果没有指定 query,则返回所有保存的元素。

final all = await detabase.fetch();

指定 query 返回所有匹配的元素。

final result = await detabase.fetch(
  query: [DetaQuery('year').lessThanOrEqualTo(2000).and('name').prefix('C')],
);

运行测试 🧪

要运行所有单元测试,请使用以下命令:

flutter test --coverage --test-randomize-ordering-seed random

要查看生成的覆盖率报告,可以使用 coverde

# 生成覆盖率报告
$ coverde report

示例代码

import 'package:deta/deta.dart';
import 'package:dio/dio.dart';
import 'package:dio_client_deta_api/dio_client_deta_api.dart';
import 'package:equatable/equatable.dart';

const projectKey = 'put-your-proyect-key-here';

Future<void> main(List<String> args) async {
  // 声明Deta类,接收私有凭证作为参数
  final deta = Deta(
    projectKey: projectKey,
    client: DioClientDetaApi(dio: Dio()),
  );

  // 定义DetaBase,接收数据库名称作为参数
  final detabase = deta.base('lenguages');

  // 保存一个条目,如果键已存在则更新
  await detabase.put({
    'key': 'dart-g',
    'name': 'Dart',
    'description':
        'Dart is a general-purpose programming language that adds strong '
            'support for modularity, co-variant return types, and a strong '
            'emphasis on type safety.',
    'creator': 'Google',
    'year': 2012,
  });

  // 保存一个元素列表,该列表最多只能包含20个元素
  await detabase.putMany(
    items: lenguages.map((lenguage) => lenguage.toJson()).toList(),
  );

  // 保存一个元素,类似于put,但如果该元素已存在,则会抛出异常
  await detabase.insert({
    'key': 'r-f',
    'name': 'R',
    'description': 'R is a programming language and software environment '
        'for statistical computing and graphics.',
    'creator': 'R Foundation',
    'year': 1995,
  });

  // 更新元素,需要传递整个元素,包括更新和未更改的部分
  await detabase.update(
    key: 'ruby-ym',
    item: <String, dynamic>{
      'key': 'ruby-ym',
      'name': 'Ruby',
      'description': 'Ruby is a dynamic, open source, general-purpose '
          'programming language with a focus on simplicity and productivity.',
      'creator': 'Yukihiro Matsumoto',
      'year': 1995,
    },
  );

  // 获取特定元素
  final item = await detabase.get('ruby-ym');

  // 删除特定元素
  final wasDeleted = await detabase.delete('assembly');

  // 返回所有保存的元素
  final all = await detabase.fetch();

  // 返回所有匹配查询条件的元素
  final result = await detabase.fetch(
    query: [DetaQuery('year').lessThanOrEqualTo(2000).and('name').prefix('C')],
  );
}

模型

class Lenguage extends Equatable {
  const Lenguage({
    required this.key,
    required this.name,
    required this.description,
    required this.creator,
    required this.year,
  });

  factory Lenguage.fromJson(Map<String, dynamic> json) => Lenguage(
        key: json['key'] as String,
        name: json['name'] as String,
        description: json['description'] as String,
        creator: json['creator'] as String,
        year: json['year'] as int,
      );

  final String key;
  final String name;
  final String description;
  final String creator;
  final int year;

  Map<String, dynamic> toJson() => <String, dynamic>{
        'key': key,
        'name': name,
        'description': description,
        'creator': creator,
        'year': year,
      };

  [@override](/user/override)
  bool? get stringify => true;

  [@override](/user/override)
  List<Object> get props {
    return [
      key,
      name,
      description,
      creator,
      year,
    ];
  }
}

const lenguages = [
  Lenguage(
    key: 'kotlin-jb',
    name: 'Kotlin',
    description: 'Kotlin is a general-purpose, statically typed, '
        'compiled programming language that is type-safe, invariant, '
        'and flexible.',
    creator: 'JetBrains',
    year: 2011,
  ),
  Lenguage(
    key: 'swift-a',
    name: 'Swift',
    description: 'Swift is a general-purpose, multi-paradigm, '
        'safe, modern, compiled programming language running on '
        "Apple's iOS, OS X, and watchOS operating systems.",
    creator: 'Apple',
    year: 2014,
  ),
  Lenguage(
    key: 'java-o',
    name: 'Java',
    description: 'Java is a general-purpose, concurrent, class-based, '
        'object-oriented programming language that is specifically '
        'designed to have as few implementation dependencies as possible.',
    creator: 'Oracle',
    year: 1995,
  ),
  Lenguage(
    key: 'c#-m',
    name: 'C#',
    description: 'C# is a multi-paradigm programming language '
        'encompassing both object-oriented (class-based) and imperative '
        '(structured) programming styles.',
    creator: 'Microsoft',
    year: 2000,
  ),
  Lenguage(
    key: 'c++-b',
    name: 'C++',
    description: 'C++ is a general-purpose programming language '
        'and a multi-paradigm, generic, object-oriented, component-based, '
        'and reusable programming language.',
    creator: 'Borland',
    year: 1983,
  ),
  Lenguage(
    key: 'js-m',
    name: 'JavaScript',
    description: 'JavaScript is a high-level, dynamic, untyped, '
        'event-based, and prototype-based scripting language.',
    creator: 'Mozilla',
    year: 1995,
  ),
  Lenguage(
    key: 'php-rl',
    name: 'PHP',
    description: 'PHP is a server-side scripting language designed '
        'for web development but also used as a general-purpose '
        'general-purpose programming language.',
    creator: 'Rasmus Lerdorf',
    year: 1995,
  ),
  Lenguage(
    key: 'python-gvr',
    name: 'Python',
    description: 'Python is a widely used high-level, general-purpose, '
        'and interpreted programming language. Its design philosophy '
        'aims to make it easy to read and write code, to get '
        'results quickly, and to avoid common pitfalls.',
    creator: 'Guido van Rossum',
    year: 1991,
  ),
  Lenguage(
    key: 'ruby-ym',
    name: 'Ruby',
    description: 'Ruby is a dynamic, open source, general-purpose '
        'programming language with a focus on simplicity and productivity.',
    creator: 'Yukihir Matsumoto',
    year: 1995,
  ),
  Lenguage(
    key: 'scala-mo',
    name: 'Scala',
    description: 'Scala is a general-purpose programming language '
        'designed to make writing functional and concise.',
    creator: 'Martin dersky',
    year: 2003,
  ),
  Lenguage(
    key: 'go-g',
    name: 'Go',
    description: 'Go is an open source programming language that '
        'conforms to the Common Language Infrastructure (CLI) '
        'standard.',
    creator: 'Google',
    year: 2009,
  ),
  Lenguage(
    key: 'rust-gh',
    name: 'Rust',
    description: 'Rust is a systems programming language that '
        'conforms to the Common Language Infrastructure (CLI) '
        'standard.',
    creator: 'Graydon Hoare',
    year: 2009,
  ),
  Lenguage(
    key: 'c-dr',
    name: 'C',
    description: 'C is a general-purpose, imperative computer '
        'programming language, supporting structured programming, '
        'lexical variable scope, and recursion.',
    creator: 'Dennis Ritchie',
    year: 1972,
  )
];

更多关于Flutter数据同步与后端服务插件deta的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据同步与后端服务插件deta的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中实现数据同步与后端服务时,deta(现称为Supabase)是一个非常流行的选择。Supabase 提供了实时的数据库和身份验证服务,非常适合构建数据同步的应用。下面是一个简单的代码案例,展示如何在Flutter中使用supabase-dart插件来同步数据。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加supabase-dart依赖:

dependencies:
  flutter:
    sdk: flutter
  supabase_dart: ^0.2.11  # 请检查最新版本号

2. 初始化Supabase客户端

在你的Flutter应用的入口文件(通常是main.dart)中,初始化Supabase客户端:

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

void main() {
  // 替换为你的Supabase项目URL和匿名密钥
  final client = SupabaseClient(
    supabaseUrl: "https://<你的项目ID>.supabase.co",
    supabaseAnonKey: "<你的匿名密钥>"
  );

  // 你可以在这里将client传递给其他小部件或作为全局状态管理
  runApp(MyApp(client: client));
}

class MyApp extends StatelessWidget {
  final SupabaseClient client;

  MyApp({required this.client});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Supabase Data Sync Example'),
        ),
        body: Center(
          child: DataSyncExample(client: client),
        ),
      ),
    );
  }
}

3. 数据同步示例

下面是一个简单的例子,展示如何从Supabase数据库中获取数据并在UI中显示,同时监听实时更新:

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

class DataSyncExample extends StatefulWidget {
  final SupabaseClient client;

  DataSyncExample({required this.client});

  @override
  _DataSyncExampleState createState() => _DataSyncExampleState();
}

class _DataSyncExampleState extends State<DataSyncExample> {
  late final RealtimeClient realtime;
  late final List<Map<String, dynamic>> items = [];
  late final Subscription subscription;

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

    // 初始化实时客户端
    realtime = widget.client.realtime;

    // 从数据库中获取初始数据
    fetchData();

    // 订阅实时更新
    subscription = realtime.from('your_table_name').on('*', (payload) {
      setState(() {
        // 处理实时更新
        if (payload.event == 'INSERT') {
          items.add(payload.newRecord);
        } else if (payload.event == 'UPDATE') {
          int index = items.indexWhere((item) => item['id'] == payload.newRecord['id']);
          if (index != -1) {
            items[index] = payload.newRecord;
          }
        } else if (payload.event == 'DELETE') {
          items.removeWhere((item) => item['id'] == payload.oldRecord['id']);
        }
      });
    });
  }

  void fetchData() async {
    try {
      final response = await widget.client.from('your_table_name').select().execute();
      setState(() {
        items = response.data!;
      });
    } catch (error) {
      print('Error fetching data: $error');
    }
  }

  @override
  void dispose() {
    // 取消订阅
    subscription.unsubscribe();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: items.length,
      itemBuilder: (context, index) {
        final item = items[index];
        return ListTile(
          title: Text('ID: ${item['id']}, Name: ${item['name']}'),
        );
      },
    );
  }
}

注意事项

  1. 替换占位符:确保将<你的项目ID><你的匿名密钥>替换为你的实际Supabase项目信息。
  2. 表名:将'your_table_name'替换为你实际使用的表名。
  3. 权限:根据你的需求,可能需要设置适当的权限(如使用认证密钥而不是匿名密钥)。

这个示例展示了如何在Flutter中使用supabase-dart插件进行数据同步和实时更新。根据实际需求,你可以进一步扩展和定制这个示例。

回到顶部