使用flutter_moor时如何停止多次创建类数据库文件?

Posted

技术标签:

【中文标题】使用flutter_moor时如何停止多次创建类数据库文件?【英文标题】:How to stop class database file getting created multiple times when using flutter_moor? 【发布时间】:2021-02-04 06:26:38 【问题描述】:

每当我在我的颤振应用程序中向我的数据库添加新行时,我都会收到此错误:

警告(moor):您似乎已经多次创建了数据库类AppDatabase。当这两个数据库使用相同的 QueryExecutor 时,会出现竞争条件并可能损坏数据库。

我阅读了不同的文章并推断出我可能不止一次调用了构造函数,但仍然没有找到解决方法。

这里有一些代码sn-ps供初步参考:

pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  basic_utils: ^2.6.3
  cupertino_icons: ^1.0.0
  flutter_blue: ^0.7.3
  google_fonts: ^1.1.1
  http: ^0.12.2
  json_annotation: ^3.1.1
  logging: ^0.11.4
  #moor: ^3.4.0
  moor_flutter: ^3.1.0
  provider: ^4.3.3
  sqflite: ^1.3.2+3
  sqlite3_flutter_libs: ^0.3.0
  url_launcher: ^5.7.10

dev_dependencies:
  flutter_test:
    sdk: flutter
  build_runner: ^1.9.0
  chopper_generator: ^3.0.4
  json_serializable: ^3.3.0
  moor_generator: ^3.4.1

moor_database.dart:

import 'package:moor_flutter/moor_flutter.dart';
part 'moor_database.g.dart';

@DataClassName('AvailableFunctionTable') //Final Table Name
class AvailableFunctionsTable extends Table 
  IntColumn get id => integer()();
  TextColumn get make => text().withLength(min: 1, max: 50)();
  TextColumn get model => text().withLength(min: 1, max: 50).nullable()();
  IntColumn get year => integer().nullable()();
  TextColumn get functionType => text().withLength(min: 1, max: 100)();
  TextColumn get functionName => text().withLength(min: 1, max: 100)();

  @override
  Set<Column> get primaryKey => id;


@UseMoor(tables: [AvailableFunctionsTable])
class AppDatabase extends _$AppDatabase 
  AppDatabase()
      : super(FlutterQueryExecutor.inDatabaseFolder(
            path: "db.sqlite", logStatements: true));
  int get schemaVersion => 1;

  Future<List<AvailableFunctionTable>> getAllAvailableFunctionss() =>
      select(availableFunctionsTable).get();

  Stream<List<AvailableFunctionTable>> watchAllAvailableFunctionss() =>
      select(availableFunctionsTable).watch();

  Future insertAvailableFunctions(AvailableFunctionTable availableFunctions) =>
      into(availableFunctionsTable).insert(availableFunctions);

  Future updateAvailableFunctions(AvailableFunctionTable availableFunctions) =>
      update(availableFunctionsTable).replace(availableFunctions);

  Future deleteAvailableFunctions(AvailableFunctionTable availableFunctions) =>
      delete(availableFunctionsTable).delete(availableFunctions);


main.dart:

void main() 
  runApp(AvFunctionsScreen());


class AvFunctionsScreen extends StatefulWidget 
  @override
  _AvFunctionsScreenState createState() => _AvFunctionsScreenState();


class _AvFunctionsScreenState extends State<AvFunctionsScreen> 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData.dark(),
      home: Scaffold(
        appBar: AppBar(
          title: Text("AvFunctionsScreen List"),
        ),
        body: SingleChildScrollView(child: NewEntry()),
      ),
    );
  


class NewEntry extends StatefulWidget 
  @override
  _NewEntryState createState() => _NewEntryState();


class _NewEntryState extends State<NewEntry> 
  TextEditingController idController = TextEditingController();

  TextEditingController makeController = TextEditingController();

  TextEditingController modelController = TextEditingController();
  TextEditingController functionNameController = TextEditingController();

  TextEditingController functionTypeController = TextEditingController();
  TextEditingController yearController = TextEditingController();
  bool isloading = false;

  @override
  Widget build(BuildContext context) 
    return Column(
      children: <Widget>[
        TextField(
          decoration: InputDecoration(hintText: 'id'),
          keyboardType: TextInputType.number,
          controller: idController,
        ),
        TextField(
          decoration: InputDecoration(hintText: 'make'),
          keyboardType: TextInputType.text,
          controller: makeController,
        ),
        TextField(
          decoration: InputDecoration(hintText: 'model'),
          keyboardType: TextInputType.text,
          controller: modelController,
        ),
        TextField(
          decoration: InputDecoration(hintText: 'year'),
          keyboardType: TextInputType.number,
          controller: yearController,
        ),
        TextField(
          decoration: InputDecoration(hintText: 'func type'),
          keyboardType: TextInputType.text,
          controller: functionTypeController,
        ),
        TextField(
          decoration: InputDecoration(hintText: 'func name'),
          keyboardType: TextInputType.text,
          controller: functionNameController,
        ),
        RaisedButton(
          onPressed: () 
            setState(() 
              AppDatabase().insertAvailableFunctions(AvailableFunctionTable(
                id: int.parse(idController.text),
                make: makeController.text,
                model: modelController.text,
                year: int.parse(yearController.text),
                functionName: functionNameController.text,
                functionType: functionTypeController.text,
              ));
              idController.clear();
              makeController.clear();
              modelController.clear();
              yearController.clear();
              functionNameController.clear();
              functionTypeController.clear();
            );
          ,
          color: Colors.green,
          child: Text("Add info"),
        ),
        Container(
          height: 700,
          width: double.infinity,
          child: StreamBuilder(
            stream: AppDatabase().watchAllAvailableFunctionss(),
            builder: (context,
                AsyncSnapshot<List<AvailableFunctionTable>> snapshot) 
              return ListView.builder(
                itemBuilder: (_, index) 
                  return Card(
                    color: Colors.blueAccent,
                    child: ListTile(
                        leading: CircleAvatar(
                          child: Text('$index + 1'),
                          radius: 20,
                        ),
                        title: Text(snapshot.data[index].id.toString() +
                            ' ' +
                            snapshot.data[index].year.toString()),
                        subtitle: Text(snapshot.data[index].make +
                            ' ' +
                            snapshot.data[index].model +
                            ' ' +
                            snapshot.data[index].functionType +
                            ' ' +
                            snapshot.data[index].functionName),
                        trailing: IconButton(
                          icon: Icon(Icons.delete_outline),
                          onPressed: () 
                            setState(() 
                              AppDatabase().deleteAvailableFunctions(
                                  snapshot.data[index]);
                            );
                          ,
                          color: Colors.red,
                        )),
                  );
                ,
                itemCount: snapshot?.data?.length,
              );
            ,
          ),
        )
      ],
    );
  


虽然我的输出正常并且应用程序似乎工作正常,但每次热重启时它都会在调试控制台中给我一个错误:

在 null 上调用了方法“[]”。 接收方:空 尝试调用:''(实际错误有一对方括号,后跟一对圆括号,圆括号之间有一个零而不是引号)

所以,我想摆脱这两个错误,以便开始集成我的 API

提前致谢!

【问题讨论】:

【参考方案1】:

您不应在应用程序中多次调用AppDatabase()。每次调用AppDatabase() 都会创建一个新实例,最终会得到许多数据库实例。最好的方法是创建一次并将其提供给所需的组件。另外,检查 Dart 中的 Singleton 模式。

【讨论】:

以上是关于使用flutter_moor时如何停止多次创建类数据库文件?的主要内容,如果未能解决你的问题,请参考以下文章

jQuery:停止在多次翻转时重复动画?

使用 Saxon 时如何停止样式表文件锁定?

如何停止多次接收相同的短信?

在标签中找到注释值 21。这大于类数

在多次悬停时停止动画

Gmail 自动回复脚本 - 如何停止多次回复?