Вопрос или проблема
Я пытаюсь отобразить полученные элементы через плитку списка новостей в своем приложении, но, похоже, данные не отображаются. Все еще стоит на “Потоки все еще загружаются”, и я не знаю, что происходит. Поэтому я представлю все соответствующие классы.
Это блок историй и класс поставщика историй.
import 'package:flutter/material.dart';
import 'package:new_flutter/src/blocs/stories_bloc.dart';
export 'stories_bloc.dart';
class StoriesProvider extends InheritedWidget {
final StoriesBloc bloc;
StoriesProvider({required Key super.key, required super.child})
: bloc = StoriesBloc();
@override
bool updateShouldNotify(oldWidget) => true;
static StoriesBloc of(BuildContext context) {
final StoriesProvider? provider =
context.dependOnInheritedWidgetOfExactType<StoriesProvider>();
if (provider == null) {
throw FlutterError('StoriesProvider не найден в дереве виджетов');
}
return provider.bloc;
// return (context.dependOnInheritedWidgetOfExactType(aspect: StoriesProvider)
// as StoriesProvider)
// .bloc;
}
}
Класс Stories_bloc:
import 'package:new_flutter/src/resources/repository.dart';
import 'package:rxdart/rxdart.dart';
import '../models/item_model.dart';
class StoriesBloc {
final Repository _repository = Repository();
final _topIds = PublishSubject<List<int>>();
final _itemsOutput = BehaviorSubject<Map<int, Future<ItemModel?>>>();
final _itemsFetcher = PublishSubject<int>();
///Геттеры для потоков
Stream<List<int>> get topIds => _topIds.stream;
Stream<Map<int, Future<ItemModel?>>> get items => _itemsOutput.stream;
///Геттеры для входных данных
Function(int) get fetchItem => _itemsFetcher.sink.add;
StoriesBloc() {
_itemsFetcher.stream.transform(_itemsTransformer()).pipe(_itemsOutput);
}
fetchTopIds() async {
final ids = await _repository.fetchTopIds();
_topIds.sink.add(ids);
}
_itemsTransformer() {
return ScanStreamTransformer(
(Map<int, Future<ItemModel?>> cache, int id, _) {
cache[id] = _repository.fetchItems(id);
return cache;
},
<int, Future<ItemModel>>{},
);
}
}
Теперь я покажу вам классы списка новостей и плитки списка новостей соответственно:
Это класс плитки списка новостей:
import 'package:flutter/material.dart';
import 'package:new_flutter/src/blocs/stories_provider_bloc.dart';
import 'package:new_flutter/src/models/item_model.dart';
class NewsListTile extends StatelessWidget {
final int? itemId;
const NewsListTile({super.key, this.itemId});
@override
Widget build(BuildContext context) {
final bloc = StoriesProvider.of(context);
return StreamBuilder(
stream: bloc.items,
builder:
(context, AsyncSnapshot<Map<int, Future<ItemModel?>>> snapshot) {
if (!snapshot.hasData) {
return Text('Потоки все еще загружаются');
}
return FutureBuilder(
future: snapshot.data![itemId],
builder: (context, AsyncSnapshot<ItemModel?> itemSnapshot) {
if (!itemSnapshot.hasData) {
return Text('Элемент $itemId все еще загружается');
}
return Text(itemSnapshot.data!.title);
},
);
});
}
}
А это класс списка новостей, соответственно:
import 'package:flutter/material.dart';
import 'package:new_flutter/src/blocs/stories_provider_bloc.dart';
import 'package:new_flutter/src/widgets/news_list_tile.dart';
class NewsList extends StatelessWidget {
const NewsList({super.key});
@override
Widget build(BuildContext context) {
final bloc = StoriesProvider.of(context);
///Это плохо!!! не делай этого.
///Временно
bloc.fetchTopIds();
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.blue,
elevation: 5,
title: const Text(
'Лучшие новости',
style: TextStyle(
color: Colors.white,
),
),
),
body: buildList(bloc),
);
}
Widget buildList(StoriesBloc bloc) {
return StreamBuilder(
stream: bloc.topIds,
builder: (context, AsyncSnapshot<List<int>> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
color: Colors.blue,
),
);
}
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, int index) {
bloc.fetchItem(snapshot.data![index]);
return NewsListTile(
itemId: snapshot.data![index],
);
},
);
},
);
}
}
Ответ или решение
Решение проблемы: FutureBuilder не отображает элемент списка новостей
Приветствую вас! Ваша проблема связана с тем, что элементы списка новостей в вашем приложении на Flutter не отображаются. Вместо этого пользователь видит сообщение "Streams still loading". Давайте разберемся в этом вопросе, анализируя ваш код и описывая возможные причины возникновения проблемы.
1. Понимание архитектуры приложения
Ваша архитектура приложения основана на паттерне BLoC (Business Logic Component), который позволяет эффективно управлять состоянием. Ваша структура классов, включающая StoriesProvider
, StoriesBloc
, NewsListTile
и NewsList
, выглядит хорошо. Однако необходимо убедиться, что потоки данных правильно обрабатываются и выводят ожидаемые результаты.
2. Проблемы с потоками данных
Ваша первоочередная задача — убедиться, что данные действительно загружаются и потоки данных функционируют должным образом. Рассмотрим несколько аспектов:
-
Метод fetchTopIds() в классе
StoriesBloc
: он должен заполнять потокtopIds
. Убедитесь, что вы вызываете его именно в момент инициализации вашего списка (что вы, кажется, уже делаете вNewsList
), и что метод работает корректно. -
Проверка данных: В вашем
NewsList
, после вызоваfetchTopIds()
, данные в стриме могут еще не успеть загрузиться, и это может привести к тому, что вStreamBuilder
дляtopIds
будет выводиться индикатор загрузки. Убедитесь, что методfetchTopIds()
фактически получает данные из репозитория.
3. Взаимодействие с FutureBuilder
В классе NewsListTile
вы используете FutureBuilder
, чтобы обработать данные, полученные в StreamBuilder
. Убедитесь в следующем:
-
В
FutureBuilder
у вас указаноfuture: snapshot.data![itemId]
. В этом месте необходимо удостовериться, чтоitemId
корректен, так как если он будет равен null или не будет существовать в fetched map, вы получите ошибку. -
Также, убедитесь, что ваше отображение элемента списка работает правильно. Текущий код в
FutureBuilder
ожидает данные, и если они не приходят из-за незагруженного потока, вы получите сообщение об ошибке.
4. Возможные решения
-
Проверка методов репозитория: Убедитесь, что ваш метод
fetchItems(id)
возвращает данные. Для этого можно добавить логи, чтобы проверить, вызывается ли этот метод и возвращает ли он ожидаемые данные. -
Обработка вопросов инициализации: Поскольку данные в BLoC загружаются асинхронно, убедитесь, что вы должным образом обрабатываете ситуации с "пустыми" данными. В текущий момент стоит добавить обработку для случая, если
snapshot.data
оказывается пустым вFutureBuilder
.
Пример кода для улучшения обработки ошибок:
if (snapshot.data == null || !snapshot.data!.containsKey(itemId)) {
return Text('Item not found');
}
- Логирование этапов загрузки: Вставьте логи в ключевые точки вашего кода, чтобы понимать, какая часть не работает, и где именно ваш поток данных останавливается.
Заключение
Следуя приведенным выше шагам, вы сможете идентифицировать и устранить проблемы с отображением списка новостей. Не забудьте детально проверять все потоки данных и их инициализацию. Если проблемы останутся, используйте инструменты отладки Flutter для более глубокого анализа состояния потоков. Удачи в решении вашей задачи!