#asynchronous #dart #flutter #async-await #future
#асинхронный #dart #флаттер #асинхронный -ожидание #будущее
Вопрос:
Я уже некоторое время использую basic async / await без особых проблем, и я думал, что понял, как это работает. Не могу сказать, что я эксперт в этом, но я понимаю суть этого. Я просто не могу разобраться в потоках. До сегодняшнего дня я думал, что понимаю, как они работают (в основном, реактивное программирование ala), но я не могу заставить их работать в Dart.
Я работаю над уровнем сохранения с возможностью сохранения и извлечения файлов (json). Я использовал пример FileManager в качестве ориентира.
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;
}
});
}
}
Очевидно, что это не сработает, но даже попытка ожидания цикла с использованием закомментированных частей вызывает ошибку.
В «getNotes» после проверки разрешений я хочу получить массив всех файлов в каталоге, проанализировать их как объекты заметок и вернуть результирующий массив.
Я получаю список файлов:
Stream<FileSystemEntity> fileList =
Directory(file).list(recursive: false, followLinks: false);
И для каждого из них в потоке я хочу разобрать файл в объект и добавить его в массив, чтобы вернуть в конце.
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;
Комментарии:
1. Отредактировал вопрос, чтобы сделать его более понятным. Дайте мне знать, если у вас есть какие-либо другие вопросы.
2. Все правильно понял. Вы можете преобразовать поток в будущее, если вам нужны все элементы и вы не хотите, чтобы они были по одному, используя . ToList(); в конце и возвращает это будущее в конце. Спасибо.
3. конечно, ваше приветствие
Stream#asyncMap
очень удобно, если вам нужно выполнить некоторыеFuture
действия над элементами вашегоStream
4. В чем ошибка? Включите это в сообщение, пожалуйста.
Ответ №1:
Stream.forEach()
возвращает a Future
. Ваш последний оператор return выполняется сразу после вызова for-each, но должен await
ли он.
await fileList.forEach((x) {
...
https://api.dartlang.org/stable/2.2.0/dart-async/Stream/forEach.html