Flutter数据同步与后端服务插件deta的使用
Flutter数据同步与后端服务插件deta的使用
Deta
一个用于与免费版Deta平台的HTTP API进行交互的Dart包。
警告
此客户端仅应在服务器端使用。
索引
开始使用
查看完整的示例 在这里。
安装
在 pubspec.yaml
中添加依赖:
dependencies:
deta: <version>
使用
我们声明一个类 Deta
,它接收我们的私有凭证作为参数。client
参数可以接收两种不同的实现 DioClientDetaApi
或 HttpClientDetaApi
,你需要根据你的偏好选择并添加相应的依赖项。
- DioClientDetaApi 由
dio
包的HTTP客户端使用。 - HttpClientDetaApi 由
http
包的HTTP客户端使用。
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
更多关于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']}'),
);
},
);
}
}
注意事项
- 替换占位符:确保将
<你的项目ID>
和<你的匿名密钥>
替换为你的实际Supabase项目信息。 - 表名:将
'your_table_name'
替换为你实际使用的表名。 - 权限:根据你的需求,可能需要设置适当的权限(如使用认证密钥而不是匿名密钥)。
这个示例展示了如何在Flutter中使用supabase-dart
插件进行数据同步和实时更新。根据实际需求,你可以进一步扩展和定制这个示例。