0

I am writing a flutter app and I am trying to insert some data to a local database and give back the primary key the database creates, but somehow the await keyword breaks the function that handles the database interaction. (Following code is a simplified version of my actual code, but has all the essentials and the same issue)

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

If I put breakpoints in lines 2 and 3, line 2 stops as expected, but upon resuming the program never stops for line 3 (i let it run for almost 15 minutes to make sure and nothing happened).

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.}

If I remove the o.id = await in line 21 it works. The problem is, that I need the return value at this spot. Line 7-10 work with inserting and ignoring the return value, but as soon as I try to query (another function same structure as insertObject just with db.query and a cast the the desired class) I need the return value again. Same problem with going through the object itself (although for some reason when going through the object the return value works just fine and I can set the attribute inside the class).

When running the app it just stays in a endless loading screen, despite the while loop concluding and the line 15 printing to the console as it should. I thought this could be because await 'creating' a new thread, but if a new thread means the return value gets lost then I don't see any point in using async-await. Why does the function insertObjekt just stop after one line and how can make sure I get the desired return value so the database can be read?

Edit to add: The requested implementation of _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.}
mr.jogurt
  • 43
  • 8
  • 1
    Show us your _database implementation – Ozan Taskiran Aug 31 '23 at 19:51
  • "despite the while loop concluding and the line 15 printing to the console as it should". That is not plausible with this code. `while (currentObjekt == null) { sleep(...); }` will never allow asynchronous operations in that isolate to make any progress. See https://stackoverflow.com/a/56707357/. It appears that loop is trying to make an asynchronous operations synchronous; there is no supported way to do that in Dart. Do not perform asynchronous work in constructors. [If you need to do asynchronous initialization, use a `static` method](https://stackoverflow.com/a/57985673/). – jamesdlin Aug 31 '23 at 20:47
  • 2
    And no, `await` does not create any new thread. Dart isolates are single-threaded. `await` simply *yields*; it's syntactic sugar for returning a `Future` and registering completion callbacks for you. – jamesdlin Aug 31 '23 at 20:50
  • @OzanTaskiran i added the implementation in the post – mr.jogurt Sep 02 '23 at 09:31
  • @jamesdlin then i don't understand even less than i think i did. The line `print('concluded');` fires and prints to the console. The loop with sleep was intended to check every 10ms if currentObjekt has been set, because my initial thought was that the database actions took longer than it takes the code to get to the point where currentObjekt is needed/used. Using a static method would help with readability but i dont think it really tackles my problem – mr.jogurt Sep 02 '23 at 09:37
  • @mr.jogurt If "concluded" is printed, then the code you're running isn't the code you've shown. It's not possible for `currentObjekt` to ever be assigned because your `while(...) { sleep(...)` loop blocks the entire isolate. If you don't believe me, try running https://gist.githubusercontent.com/jamesderlin/a0b4c6326773c1ec172f6f625048f223/raw/1d304dfbb1f81706d3cfdd5411e5c8b9700b9d60/broken_sleep.dart. – jamesdlin Sep 02 '23 at 16:05
  • "Using a static method would help with readability but i dont think it really tackles my problem" It would tackle your problem by allowing you to replace your broken `sleep` loop with `await initialize();`. – jamesdlin Sep 02 '23 at 16:06

0 Answers0