Stream and Future in Dart
Stream.forEach()
returns a Future
. Your last return statement runs immediately after the for-each call, but should await
it.
await fileList.forEach((x) {
...
https://api.dartlang.org/stable/2.2.0/dart-async/Stream/forEach.html
vale
Updated on December 10, 2022Comments
-
vale over 1 year
I've been using basic async/await for some time without many problems and I thought I understood how it worked. Can't say I'm an expert in it, but I understadn the gist of it. I just can't get my head around Streams though. Before today I thought I understood how they worked (basically ala Reactive Programming), but I can't get them to work in Dart.
I'm working on a persistance layer with the possibility of saving and retrieving (json) files. I've been using the fileManager example as a guideline.
import 'dart:io'; import 'dart:async'; import 'package:intl/intl.dart'; //date import 'package:markdowneditor/model/note.dart';//Model import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart' as p; import 'package:flutter/foundation.dart'; //log import 'package:simple_permissions/simple_permissions.dart';//OS permissions class FileManager { static final FileManager _singleton = new FileManager._internal(); factory FileManager() { return _singleton; } FileManager._internal(); Future<String> get _localPath async { final directory = (await getApplicationDocumentsDirectory()).toString(); return p.join(directory, "notes"); //path takes strings and not Path objects } Future<File> writeNote(Note note) async { var file = await _localPath; file = p.join( file, DateFormat('kk:mm:ssEEEMMd').format(DateTime.now()) + " " + note.title); //add timestamp to title // Write the file SimplePermissions.requestPermission(Permission.WriteExternalStorage) .then((value) { if (value == PermissionStatus.authorized) { return File(file).writeAsString('$note'); } else { SimplePermissions.openSettings(); return null; } }); } Future<List<Note>> getNotes() async { //need file access permission on android. use https://pub.dartlang.org/packages/simple_permissions#-example-tab- final file = await _localPath; SimplePermissions.requestPermission(Permission.ReadExternalStorage) .then((value) { if (value == PermissionStatus.authorized) { try { Stream<FileSystemEntity> fileList = Directory(file).list(recursive: false, followLinks: false); // await for(FileSystemEntity s in fileList) { print(s); } List<Note> array = []; fileList.forEach((x) { if (x is File) { var res1 = ((x as File).readAsString()).then((value2) { Note note = Note.fromJsonResponse(value2); return note; }).catchError((error) { debugPrint('is not file content futurestring getNoteError: $x'); return null; }); var array2 = res1.then((value3) { array.add(value3); return array; }); //? } else { debugPrint('is not file getNoteError: $x'); } }); // Add the file to the files array //Return the Future<List<Note>> return array; } catch (e) { debugPrint('getNoteError: $e'); // If encountering an error, return 0 return null; } } else { SimplePermissions.openSettings(); return null; } }); } }
Obviously as it is it won't work, but even trying to await the loop using the commented out parts raises an error.
In "getNotes", after checking the permissions I want to get an array of all the files in the directory, parse them as Note objects and return the resulting array.
I get the list of files:
Stream<FileSystemEntity> fileList = Directory(file).list(recursive: false, followLinks: false);
And for each one of them in the stream I want to parse the file into an object and append it to an array to return at the end.
List<Note> array = []; fileList.forEach((x) { if (x is File) { var res1 = ((x as File).readAsString()).then((value2) { Note note = Note.fromJsonResponse(value2); return note; }).catchError((error) { debugPrint('is not file content futurestring getNoteError: $x'); return null; }); var array2 = res1.then((value3) { array.add(value3); return array; }); //? } else { debugPrint('is not file getNoteError: $x'); } }); // Add the file to the files array //Return the Future<List<Note>> return array;
-
vale about 5 yearsEdited the question to make it clearer. Let me know if you have any other question.
-
vale about 5 yearsAllright got it. You can convert a stream to a Future if you need all elements and don't want them one by one by using .toList(); at the end and return that future in the end. Thanks.
-
pskink about 5 yearssure, your welcome,
Stream#asyncMap
is very handy if you have to perform someFuture
actions on the elements of yourStream
-
Jacob Phillips about 5 yearsWhat is the error? Include it in the post please.
-