Flutter云端数据库管理插件agconnect_clouddb的使用

Flutter云端数据库管理插件agconnect_clouddb的使用

简介

Cloud DB 是一种设备与云协同工作的数据库产品,提供了设备与云之间的数据协同管理能力、统一的数据模型以及各种数据管理API。

安装插件

在 Flutter 项目的 pubspec.yaml 文件中添加依赖项:

dependencies:
  agconnect_clouddb: ^1.9.0+300

然后在终端运行以下命令以添加依赖项:

flutter pub get

更多详细信息,请参阅开始使用 Flutter

开发指南

使用

您可以访问 此处 获取更多使用信息。

参考

您可以访问 此处 获取更多引用信息。

许可证

Cloud DB 插件的许可证为:Apache License, version 2.0

完整示例代码

以下是一个完整的示例代码,展示了如何使用 agconnect_clouddb 插件进行基本操作。

/*
 * Copyright (c) 2021-2023. Huawei Technologies Co., Ltd. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import 'dart:async';

import 'package:agconnect_auth/agconnect_auth.dart';
import 'package:agconnect_clouddb/agconnect_clouddb.dart';
import 'package:flutter/material.dart';

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

class _App extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: _Home(),
    );
  }
}

class _Home extends StatefulWidget {
  [@override](/user/override)
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<_Home> {
  final String _zoneName = 'demo';
  final String _objectTypeName = 'BookInfo';
  AGConnectCloudDBZone? _zone;
  String? _currentUserUid;
  StreamSubscription<AGConnectCloudDBZoneSnapshot?>? _snapshotSubscription;
  StreamSubscription<String?>? _onEvent;
  StreamSubscription<bool?>? _onDataEncryptionKeyChanged;
  bool _isBusy = false;

  [@override](/user/override)
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) async {
      try {
        await _initCurrentUser();
        await AGConnectCloudDB.getInstance().initialize();
        await AGConnectCloudDB.getInstance().createObjectType();
        _onEvent = AGConnectCloudDB.getInstance().onEvent().listen((String? event) {
          _showDialog(context, 'On Event: $event');
        });
        _onDataEncryptionKeyChanged = AGConnectCloudDB.getInstance()
            .onDataEncryptionKeyChanged()
            .listen((bool? data) {
          _showDialog(context, 'Data Encryption Key Changed: $data');
        });
      } catch (e) {
        _showDialog(context, 'ERROR', e is FormatException ? e.message : e);
      }
    });
  }

  [@override](/user/override)
  void dispose() {
    _snapshotSubscription?.cancel();
    _onEvent?.cancel();
    _onDataEncryptionKeyChanged?.cancel();
    super.dispose();
  }

  Future<void> _initCurrentUser() async {
    final AGCUser? currentUser = await AGCAuth.instance.currentUser;
    if (currentUser != null) {
      setState(() => _currentUserUid = currentUser.uid);
    } else {
      final SignInResult signInResult = await AGCAuth.instance.signInAnonymously();
      if (signInResult.user != null) {
        setState(() => _currentUserUid = signInResult.user?.uid);
      } else {
        setState(() => _currentUserUid = '???');
      }
    }
  }

  void _showDialog(BuildContext context, String title, [dynamic content]) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text(title),
          content: content == null
              ? null
              : SingleChildScrollView(
                  physics: const BouncingScrollPhysics(),
                  child: Text('$content'),
                ),
          actions: [
            TextButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: const Text("Close"),
            ),
          ],
        );
      },
    );
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Scaffold(
          appBar: AppBar(
            title: const Text("AGC Cloud DB Demo"),
            actions: <Widget>[
              IconButton(
                icon: const Icon(Icons.refresh),
                onPressed: () async {
                  setState(() => _isBusy = true);
                  await AGCAuth.instance.signOut();
                  setState(() => _currentUserUid = null);
                  await _initCurrentUser();
                  setState(() => _isBusy = false);
                },
              ),
            ],
          ),
          body: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Padding(
                padding: const EdgeInsets.all(16),
                child: Text('UserID: $_currentUserUid'),
              ),
              Expanded(
                child: ListView(
                  padding: const EdgeInsets.all(16),
                  physics: const BouncingScrollPhysics(),
                  children: <Widget>[
                    _buildGroup(
                      children: <Widget>[
                        _buildButton(
                          text: 'openCloudDBZone',
                          onTap: () async {
                            if (_zone != null) {
                              throw FormatException(
                                  'Zone object is not null. First try close zone.',
                                  _zone);
                            }
                            _zone = await AGConnectCloudDB.getInstance()
                                .openCloudDBZone(
                              zoneConfig: AGConnectCloudDBZoneConfig(
                                  zoneName: _zoneName),
                            );
                          },
                        ),
                        _buildButton(
                          text: 'openCloudDBZone2',
                          onTap: () async {
                            if (_zone != null) {
                              throw FormatException(
                                  'Zone object is not null. First try close zone.',
                                  _zone);
                            }
                            _zone = await AGConnectCloudDB.getInstance()
                                .openCloudDBZone2(
                              zoneConfig: AGConnectCloudDBZoneConfig(
                                  zoneName: _zoneName),
                            );
                          },
                        ),
                        _buildButton(
                          text: 'closeCloudDBZone',
                          onTap: () async {
                            if (_zone == null) {
                              throw FormatException(
                                  'Zone object is null. First try open zone.',
                                  _zone);
                            }
                            await AGConnectCloudDB.getInstance()
                                .closeCloudDBZone(zone: _zone!);
                            _zone = null;
                          },
                        ),
                        _buildButton(
                          text: 'deleteCloudDBZone',
                          onTap: () async =>
                              await AGConnectCloudDB.getInstance()
                                  .deleteCloudDBZone(zoneName: _zoneName),
                        ),
                      ],
                    ),
                    _buildGroup(
                      children: <Widget>[
                        _buildButton(
                          text: 'getCloudDBZoneConfig',
                          onTap: () async {
                            if (_zone == null) {
                              throw FormatException(
                                  'Zone object is null. First try open zone.',
                                  _zone);
                            }
                            return await _zone!.getCloudDBZoneConfig();
                          },
                        ),
                        _buildButton(
                          text: 'getCloudDBZoneConfigs',
                          onTap: () async =>
                              await AGConnectCloudDB.getInstance()
                                  .getCloudDBZoneConfigs(),
                        ),
                      ],
                    ),
                    const Divider(height: 32),
                    _buildGroup(
                      children: <Widget>[
                        _buildButton(
                          text: 'enableNetwork',
                          onTap: () async =>
                              await AGConnectCloudDB.getInstance()
                                  .enableNetwork(zoneName: _zoneName),
                        ),
                        _buildButton(
                          text: 'disableNetwork',
                          onTap: () async =>
                              await AGConnectCloudDB.getInstance()
                                  .disableNetwork(zoneName: _zoneName),
                        ),
                      ],
                    ),
                    _buildGroup(
                      children: <Widget>[
                        _buildButton(
                          text: 'setUserKey',
                          onTap: () async =>
                              await AGConnectCloudDB.getInstance().setUserKey(
                                  userKey: '123456789', userReKey: ''),
                        ),
                        _buildButton(
                          text: 'updateDataEncryptionKey',
                          onTap: () async =>
                              await AGConnectCloudDB.getInstance()
                                  .updateDataEncryptionKey(),
                        ),
                      ],
                    ),
                    const Divider(height: 32),
                    _buildGroup(
                      children: <Widget>[
                        _buildButton(
                          text: 'subscribeSnapshot',
                          onTap: () async {
                            if (_snapshotSubscription == null) {
                              if (_zone == null) {
                                throw FormatException(
                                    'Zone object is null. First try open zone.',
                                    _zone);
                              }
                              final Stream<AGConnectCloudDBZoneSnapshot?>
                                  stream = await _zone!.subscribeSnapshot(
                                query: AGConnectCloudDBQuery(_objectTypeName)
                                  ..equalTo('id', 2),
                                policy: AGConnectCloudDBZoneQueryPolicy
                                    .POLICY_QUERY_DEFAULT,
                              );
                              _snapshotSubscription = stream.listen(
                                  (AGConnectCloudDBZoneSnapshot? snapshot) {
                                _showDialog(
                                    context, 'subscribeSnapshot', snapshot);
                              });
                            }
                          },
                        ),
                        _buildButton(
                          text: 'removeSnapshot',
                          onTap: () async =>
                              _snapshotSubscription
                                  ?.cancel()
                                  .then((_) => _snapshotSubscription = null),
                        ),
                      ],
                    ),
                    _buildGroup(
                      children: <Widget>[
                        _buildButton(
                          text: 'executeUpsert',
                          onTap: () async {
                            if (_zone == null) {
                              throw FormatException(
                                  'Zone object is null. First try open zone.',
                                  _zone);
                            }
                            final int count = await _zone!.executeUpsert(
                              objectTypeName: _objectTypeName,
                              entries: <Map<String, dynamic>>[
                                <String, dynamic>{
                                  'id': 1,
                                  'bookName': 'Book Name - 1',
                                  'price': 14.80,
                                },
                                <String, dynamic>{
                                  'id': 2,
                                  'bookName': 'Book Name - 2',
                                  'price': 22.99,
                                },
                                <String, dynamic>{
                                  'id': 3,
                                  'bookName': 'Book Name - 3',
                                  'price': 5.60,
                                },
                              ],
                            );
                            return '$count objects successfully written.';
                          },
                        ),
                        _buildButton(
                          text: 'executeDelete',
                          onTap: () async {
                            if (_zone == null) {
                              throw FormatException(
                                  'Zone object is null. First try open zone.',
                                  _zone);
                            }
                            final int count = await _zone!.executeDelete(
                              objectTypeName: _objectTypeName,
                              entries: <Map<String, dynamic>>[
                                <String, dynamic>{
                                  'id': 2,
                                },
                              ],
                            );
                            return '$count objects successfully deleted.';
                          },
                        ),
                        _buildButton(
                          text: 'runTransaction',
                          onTap: () async {
                            if (_zone == null) {
                              throw FormatException(
                                  'Zone object is null. First try open zone.',
                                  _zone);
                            }
                            await _zone!.runTransaction(
                              transaction: AGConnectCloudDBTransaction()
                                ..executeUpsert(
                                  objectTypeName: _objectTypeName,
                                  entries: <Map<String, dynamic>>[
                                    <String, dynamic>{
                                      'id': 10,
                                      'bookName': 'Book_10',
                                      'price': 5.10,
                                    },
                                    <String, dynamic>{
                                      'id': 20,
                                      'bookName': 'Book_20',
                                      'price': 25.20,
                                    },
                                  ],
                                )
                                ..executeDelete(
                                  objectTypeName: _objectTypeName,
                                  entries: <Map<String, dynamic>>[
                                    <String, dynamic>{
                                      'id': 10,
                                    },
                                  ],
                                ),
                            );
                          },
                        ),
                      ],
                    ),
                    const Divider(height: 32),
                    _buildGroup(
                      children: <Widget>[
                        _buildButton(
                          text: 'executeQuery',
                          onTap: () async {
                            if (_zone == null) {
                              throw FormatException(
                                  'Zone object is null. First try open zone.',
                                  _zone);
                            }
                            return await _zone!.executeQuery(
                              query: AGConnectCloudDBQuery(_objectTypeName)
                                ..orderBy('price'),
                              policy: AGConnectCloudDBZoneQueryPolicy
                                  .POLICY_QUERY_DEFAULT,
                            );
                          },
                        ),
                        _buildButton(
                          text: 'executeQueryUnsynced',
                          onTap: () async {
                            if (_zone == null) {
                              throw FormatException(
                                  'Zone object is null. First try open zone.',
                                  _zone);
                            }
                            return await _zone!.executeQueryUnsynced(
                              query: AGConnectCloudDBQuery(_objectTypeName)
                                ..orderBy('price'),
                            );
                          },
                        ),
                      ],
                    ),
                    _buildGroup(
                      children: <Widget>[
                        _buildButton(
                          text: 'executeCountQuery',
                          onTap: () async {
                            if (_zone == null) {
                              throw FormatException(
                                  'Zone object is null. First try open zone.',
                                  _zone);
                            }
                            return await _zone!.executeCountQuery(
                              field: 'price',
                              query: AGConnectCloudDBQuery(_objectTypeName),
                              policy: AGConnectCloudDBZoneQueryPolicy
                                  .POLICY_QUERY_DEFAULT,
                            );
                          },
                        ),
                        _buildButton(
                          text: 'executeSumQuery',
                          onTap: () async {
                            if (_zone == null) {
                              throw FormatException(
                                  'Zone object is null. First try open zone.',
                                  _zone);
                            }
                            return await _zone!.executeSumQuery(
                              field: 'price',
                              query: AGConnectCloudDBQuery(_objectTypeName),
                              policy: AGConnectCloudDBZoneQueryPolicy
                                  .POLICY_QUERY_DEFAULT,
                            );
                          },
                        ),
                        _buildButton(
                          text: 'executeAverageQuery',
                          onTap: () async {
                            if (_zone == null) {
                              throw FormatException(
                                  'Zone object is null. First try open zone.',
                                  _zone);
                            }
                            return await _zone!.executeAverageQuery(
                              field: 'price',
                              query: AGConnectCloudDBQuery(_objectTypeName),
                              policy: AGConnectCloudDBZoneQueryPolicy
                                  .POLICY_QUERY_DEFAULT,
                            );
                          },
                        ),
                        _buildButton(
                          text: 'executeMinimalQuery',
                          onTap: () async {
                            if (_zone == null) {
                              throw FormatException(
                                  'Zone object is null. First try open zone.',
                                  _zone);
                            }
                            return await _zone!.executeMinimalQuery(
                              field: 'price',
                              query: AGConnectCloudDBQuery(_objectTypeName),
                              policy: AGConnectCloudDBZoneQueryPolicy
                                  .POLICY_QUERY_DEFAULT,
                            );
                          },
                        ),
                        _buildButton(
                          text: 'executeMaximumQuery',
                          onTap: () async {
                            if (_zone == null) {
                              throw FormatException(
                                  'Zone object is null. First try open zone.',
                                  _zone);
                            }
                            return await _zone!.executeMaximumQuery(
                              field: 'price',
                              query: AGConnectCloudDBQuery(_objectTypeName),
                              policy: AGConnectCloudDBZoneQueryPolicy
                                  .POLICY_QUERY_DEFAULT,
                            );
                          },
                        ),
                        _buildButton(
                          text: 'executeServerStatusQuery',
                          onTap: () async {
                            if (_zone == null) {
                              throw FormatException(
                                  'Zone object is null. First try open zone.',
                                  _zone);
                            }
                            return await _zone!.executeServerStatusQuery();
                          },
                        ),
                        _buildButton(
                          text: 'executeGreaterThan',
                          onTap: () async {
                            if (_zone == null) {
                              throw FormatException(
                                  'Zone object is null. First try open zone.',
                                  _zone);
                            }
                            return await _zone!.executeQuery(
                                query: AGConnectCloudDBQuery(_objectTypeName)
                                  ..greaterThan('price', 10),
                                policy: AGConnectCloudDBZoneQueryPolicy
                                    .POLICY_QUERY_DEFAULT);
                          },
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
        if (_isBusy)
          Container(
            color: Colors.black87,
            alignment: Alignment.center,
            child: const CircularProgressIndicator(),
          ),
      ],
    );
  }

  Widget _buildGroup({
    required List<Widget> children,
  }) {
    return Container(
      padding: const EdgeInsets.all(16),
      margin: const EdgeInsets.only(top: 8, bottom: 8),
      decoration: const BoxDecoration(
        color: Colors.black12,
        borderRadius: BorderRadius.all(Radius.circular(16)),
      ),
      child: Wrap(
        spacing: 8,
        runSpacing: 8,
        alignment: WrapAlignment.center,
        crossAxisAlignment: WrapCrossAlignment.center,
        children: children,
      ),
    );
  }

  Widget _buildButton({
    required String text,
    required Future<dynamic> Function() onTap,
  }) {
    return ElevatedButton(
      child: Text(
        text,
        textAlign: TextAlign.center,
      ),
      onPressed: () async {
        try {
          setState(() => _isBusy = true);
          final dynamic result = await onTap();
          _showDialog(context, 'SUCCESS', result);
        } catch (e) {
          _showDialog(context, 'ERROR', e.toString());
        } finally {
          setState(() => _isBusy = false);
        }
      },
    );
  }
}

更多关于Flutter云端数据库管理插件agconnect_clouddb的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter云端数据库管理插件agconnect_clouddb的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


agconnect_clouddb 是华为提供的用于 Flutter 应用的云端数据库管理插件,它允许开发者轻松地将数据存储在华为云数据库,并实现数据的增删改查等操作。以下是使用 agconnect_clouddb 插件的基本步骤和示例代码。

1. 环境准备

在开始之前,请确保你已经完成了以下准备工作:

  • 安装 Flutter SDK。
  • 在华为开发者联盟注册并创建应用,获取 agconnect-services.json 文件。
  • pubspec.yaml 中添加 agconnect_clouddb 依赖。

2. 添加依赖

pubspec.yaml 文件中添加 agconnect_clouddb 依赖:

dependencies:
  flutter:
    sdk: flutter
  agconnect_clouddb: ^1.4.0+300

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

3. 配置 agconnect-services.json

将下载的 agconnect-services.json 文件放置在 android/app 目录下。

4. 初始化 Huawei Mobile Services (HMS)

main.dart 中初始化 HMS:

import 'package:agconnect_clouddb/agconnect_clouddb.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await AGCCloudDB.init();
  runApp(MyApp());
}

5. 创建对象类型

在华为云数据库中,你需要定义对象类型(Object Type)。每个对象类型对应一个表,表中的字段对应对象的属性。

class Book {
  String id;
  String title;
  String author;

  Book({required this.id, required this.title, required this.author});

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'title': title,
      'author': author,
    };
  }

  factory Book.fromMap(Map<String, dynamic> map) {
    return Book(
      id: map['id'],
      title: map['title'],
      author: map['author'],
    );
  }
}

6. 创建对象类型定义

使用 AGCCloudDBZoneSchemaAGCCloudDBFieldSchema 定义对象类型:

final schema = AGCCloudDBZoneSchema('Book', '1.0.0', [
  AGCCloudDBFieldSchema('id', AGCCloudDBFieldType.TEXT, isPrimaryKey: true),
  AGCCloudDBFieldSchema('title', AGCCloudDBFieldType.TEXT),
  AGCCloudDBFieldSchema('author', AGCCloudDBFieldType.TEXT),
]);

7. 创建云数据库区域

创建云数据库区域(Zone),用于管理数据:

final zone = AGCCloudDBZone('MyZone');
await AGCCloudDB.createZone(zone);

8. 执行增删改查操作

以下是一些基本的增删改查操作示例:

插入数据

final book = Book(id: '1', title: 'Flutter Guide', author: 'John Doe');
await AGCCloudDB.executeUpsert(zone, schema, [book.toMap()]);

查询数据

final query = AGCCloudDBQueryBuilder(schema)
    .where(AGCCloudDBQueryCondition.equal('id', '1'))
    .build();
final result = await AGCCloudDB.executeQuery(zone, query);
final books = result.map((map) => Book.fromMap(map)).toList();

更新数据

final updatedBook = Book(id: '1', title: 'Flutter Advanced Guide', author: 'John Doe');
await AGCCloudDB.executeUpsert(zone, schema, [updatedBook.toMap()]);

删除数据

final query = AGCCloudDBQueryBuilder(schema)
    .where(AGCCloudDBQueryCondition.equal('id', '1'))
    .build();
await AGCCloudDB.executeDelete(zone, query);

9. 删除云数据库区域

当你不再需要某个云数据库区域时,可以将其删除:

await AGCCloudDB.deleteZone(zone);

10. 错误处理

在执行数据库操作时,建议使用 try-catch 进行错误处理:

try {
  await AGCCloudDB.executeUpsert(zone, schema, [book.toMap()]);
} catch (e) {
  print('Error: $e');
}
回到顶部