#flutter
#флаттер
Вопрос:
Когда пользователь публикует комментарий. Он сохраняет комментарий в базе данных (Mysql), но StreamProvider по какой-то причине не обновляет listview. Я могу получить доступ к поставщику и данным комментариев. Но когда я публикую новый комментарий. через метод добавления. Как я уже сказал, listview не отображает новый комментарий, который был отправлен в базу данных.
class CommentModel {
final int reportId;
final String text;
const CommentModel(this.reportId, this.text);
}
class CommentProvider {
Stream<List<CommentModel>> intStream(int reportId) {
return Stream.fromFuture(getComments(reportId));
}
Future<List<CommentModel>> getComments(int reportId) async {
final comments = await _fetchComments(reportId);
final List<CommentModel> messages = List<CommentModel>();
for (int i = 0; i < comments.length; i ) {
messages.add(CommentModel(reportId, comments[i]["text"])));
}
return messages;
}
Future<void> add(CommentModel data) async {
await _postComment(data.reportId, data.text);
}
}
MultiProvider(
providers: [
ChangeNotifierProvider<CommentProvider>(create: (_) => CommentProvider()),
StreamProvider<List<CommentModel>>(
create: (_) => CommentProvider().intStream(int.tryParse(reportData["id"])),
initialData: null,
),
],
child: CardCommentWidget(
reportId: int.tryParse(reportData["id"]),
),
),
final commentData = Provider.of<List<CommentModel>>(context);
ListView.builder(
key: PageStorageKey("commentsScroll"),
shrinkWrap: true,
itemCount: commentData.length,
itemBuilder: (BuildContext context, int index) {
final comment = commentData[index];
return Text(comment.text);
},
),
Ответ №1:
Похоже, вы просто преобразуете вывод getComments
метода в поток. Это означает, что при вызове intStream
метода вы получите поток, который выдает результаты getComments
метода только один раз. Ничто не сообщает потоку, что добавлены дополнительные элементы.
Я не могу догадаться, какую базу данных вы используете для резервного копирования и какие у нее «потоковые» возможности, но кто-то должен сообщить вашему потоку, что добавлен новый элемент. Одним из способов решить эту проблему было бы что-то вроде этого:
- Объявите a
StreamController
, который будет действовать как поток и приемник; - В
intStream
методе инициализируйтеStreamController
с результатомgetComments
метода и верните потокStreamController
; - После сохранения комментария в базе данных добавьте комментарий в
StreamController
.
В коде это может выглядеть примерно так:
class CommentProvider {
final StreamController<List<CommentModel>> _streamController;
Stream<List<CommentModel>> intStream(int reportId) {
// Initialize a new instance of the StreamController
// and emit each comment when someone starts listening
// to the stream.
if (_streamController == null) {
_streamController = StreamController<List<CommentModel>>
.broadcast(
onListen: () async => await getComments(reportId),
onErrror: (error) {
// Handle error here...
},
);
}
return _streamController.stream;
}
Future<List<CommentModel>> getComments(int reportId) async {
final comments = await _fetchComments(reportId);
final List<CommentModel> messages = List<CommentModel>();
for (int i = 0; i < comments.length; i ) {
messages.add(CommentModel(reportId, comments[i]["text"])));
}
return messages;
}
Future<void> add(CommentModel data) async {
await _postComment(data.reportId, data.text);
// Emit the updated list containing the added
// comment on the stream.
if (_streamController != null) {
final comments = await getComments(data.reportId);
_streamController?.add(comments);
}
}
}
Приведенный выше код является примером и должен работать. Возможно, вам потребуется немного изменить его, как указано в комментариях, которые являются частью примера кода. И, как я уже упоминал, некоторые базы данных напрямую поддерживают потоковую передачу (например, Firebase), которые напрямую возвращают результат запроса в виде потока и автоматически добавляют элементы в поток, когда они добавляются в базу данных и соответствуют критериям запроса. Однако я не смог вывести это из вашего кода.
Некоторые материалы для чтения по работе с StreamController
классом можно найти здесь:
- Класс StreamController;
- Использование StreamController
Редактировать:
Я обновил логику в add
методе, чтобы убедиться _streamController
, что если нет null
.
РЕДАКТИРОВАТЬ 2:
Обновлен код, чтобы возвращать поток, выдающий списки комментариев, чтобы мы могли лучше упростить ListView
класс.
Комментарии:
1. Здравствуйте, спасибо, что помогли мне. Возникла некоторая проблема, например,
add
ошибка now null.2. @printer, вы правы. Я забыл проверить
_streamController
, инициализирован ли он перед вызовомadd
функции на нем. Это может произойти при вызовеadd
перед инициализацией StreamController с использованиемintStream
метода. В этих случаях мы можем просто игнорировать вызовadd
_streamController
, поскольку мы знаем, что никто все равно не слушает.3. Ура, чувак, теперь нет нулевой ошибки. Но у меня есть вопрос, поскольку
initStream
не возвращает список комментариев. Как я могу получить доступ ко всем комментариям в моемListview.builder
. (Я использую Mysql в качестве базы данных)4. @Printer, вы правы, в этом случае было бы лучше вернуть список комментариев, поэтому я обновил пример кода, чтобы возвращать список вместо отдельных элементов. Единственным недостатком сейчас является то, что при добавлении элемента вы снова будете извлекать комментарии из базы данных.
5. Приветствую, приятель, я думаю, у меня есть четкое представление о том, как это работает сейчас 🙂