await关键字在dart内部中断数据库函数

jyztefdp  于 2023-09-28  发布在  其他
关注(0)|答案(1)|浏览(105)

我正在写一个flutter应用程序,我试图将一些数据插入到本地数据库中,给予数据库创建的主键,但不知何故,await关键字破坏了处理数据库交互的函数。(下面的代码是我的实际代码的简化版本,但具有所有的要点和相同的问题)

1.Future<int> insertObjekt(Objekt o) async {
2.  final db = await _database;
3.  return db.insert('objekt', {'name': o.name});
4.}

如果我在第2行和第3行中设置断点,第2行会按预期停止,但在恢复时,程序永远不会在第3行停止(我让它运行了近15分钟,以确保没有发生任何事情)。

1. class TestState extends ChangeNotifier {
2.   var db = tempDB;
3.   Objekt? currentObjekt;
4. 
5.   TestState(){
6.     initialize('doesn\'t work');
7.     /*Objekt o = Objekt.loaded(1, 'in constructor');
8.     db.insertObjekt(o);
9.     debugPrint('${o.id}');
10.    currentObjekt = o;// */
11.    //currentObjekt = Objekt('functions as intended', db);
12.    while(currentObjekt == null){
13.      sleep(const Duration(milliseconds: 10));
14.    }
15.    debugPrint('concluded');
16.    notifyListeners();
17.  }
18.
19.  Future<void> initialize(String name) async {
20.    Objekt o = Objekt.loaded(1, name);
21.    o.id = await db.insertObjekt(o);
22.    debugPrint('${o.id}');
23.    currentObjekt = o;
24.  }
25.}

如果我删除第21行中的o.id = await,它就可以工作。问题是,我需要在这里返回值。第7-10行用于插入和忽略返回值,但是一旦我尝试查询(另一个与insertObject相同的函数,只是使用db.query和所需类的强制转换),我就需要再次返回值。遍历对象本身也有同样的问题(尽管由于某种原因,当遍历对象时,返回值工作得很好,我可以在类中设置属性)。
当运行应用程序时,它只是停留在一个无休止的加载屏幕上,尽管while循环结束,第15行打印到控制台。我认为这可能是因为await '创建'了一个新线程,但是如果一个新线程意味着返回值丢失,那么我认为使用cnc-await没有任何意义。为什么函数insertObjekt在一行之后就停止了,如何确保我得到了想要的返回值,这样数据库就可以被读取了?
编辑以添加:_database的请求实现

1. Future<bool> openDB() async {
2.   _database = openDatabase(
3.     join(await getDatabasesPath(), 'tappDB.db'),
4.     onCreate: (db, version) async {
5.       db.execute('''
6.         CREATE TABLE objekt(
7.           id INTEGER PRIMARY KEY, 
8.           name TEXT 
9.         )''');
10.      debugPrint("DB built");
11.    },
12.    version: 4,
13.  );
14.  debugPrint("DB opened");
15.  return true;
16.}
x7yiwoj4

x7yiwoj41#

当运行应用程序时,它只是停留在一个无休止的加载屏幕上,尽管while循环结束,第15行打印到控制台。

12.    while(currentObjekt == null){
13.      sleep(const Duration(milliseconds: 10));
14.    }
15.    debugPrint('concluded');

这是不合理的与此代码。sleepblocks,因此您的循环将永远不允许该隔离中的异步操作取得任何进展。即使异步操作在不同的隔离中运行,循环隔离也永远没有机会设置currentObjekt。(另见stackoverflow.com/a/56707357)。
我认为这可能是因为await '创建'一个新线程.
不,await不会创建任何新线程。Dart隔离是单线程的。await简单地 * 产生 ;它是语法糖,用于返回Future并为您注册完成回调。
循环似乎试图使异步操作同步;在Dart中没有支持的方法来执行此操作。
不要在构造函数中执行异步工作。* If you need to do asynchronous initialization, replace the constructor with a static factory method

class TestState extends ChangeNotifier {
  var db = tempDB;
  Objekt? currentObjekt;

  TestState._();

  static Future<TestState> createTestState() async {
    var testState = TestState._();
    await testState.initialize('');
    debugPrint('concluded');
    testState.notifyListeners();
    return testState;
  }

  Future<void> initialize(String name) async {
    Objekt o = Objekt.loaded(1, name);
    o.id = await db.insertObjekt(o);
    debugPrint('${o.id}');
    currentObjekt = o;
  }
}

注意,initialize方法现在可能是多余的,可以合并到createTestState中。还要注意的是,异步操作具有内在的传染性,因此任何需要等待TestState对象被构造的函数也需要是异步的,并且调用这些函数的任何东西都需要是异步的,等等。

相关问题