【发布时间】:2021-12-31 06:59:33
【问题描述】:
我正在尝试将一个非常简单的项目组合在一起。这里的目的是从 HackerNews API 获取一些数据并将其显示给用户。在我介绍了从 top_ids 列表中获取每个项目的功能之前,代码一直运行良好。我尝试调试它,但我没有看到任何错误。但是,我仍然没有得到所需的输出(即从 top_ids 列表中获取每个项目)
news_list_screen
Widget buildList(StoriesBloc storiesBloc) {
return StreamBuilder(
stream: storiesBloc.topIds,
builder: (context, AsyncSnapshot<List<int>> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, int index) {
storiesBloc.fetchItem(snapshot.data![index]);
return NewsListTile(
itemId: snapshot.data![index],
);
},
);
},
);
}
}
class NewsListTile extends StatelessWidget {
final int itemId;
NewsListTile({required this.itemId});
Widget build(BuildContext context) {
final bloc = StoriesBlocProvider.of(context);
return StreamBuilder(
stream: bloc.items,
builder: (context, AsyncSnapshot<Map<int, Future<ItemModel>>> snapshot) {
if (!snapshot.hasData) {
return Text('Fetching item');
}
return FutureBuilder(
future: snapshot.data![itemId],
builder: (context, AsyncSnapshot<ItemModel> itemSnapshot) {
if (!itemSnapshot.hasData) {
//This gets populated with the correct ids
return Text('Still loading item $itemId');
}
return Text(itemSnapshot.data!.title);
},
);
},
);
}
}
stories_bloc
class StoriesBloc {
final _newsRepository = NewsRepository();
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 _newsRepository.fetchTopIds();
_topIds.sink.add(ids);
}
_itemsTransformer() {
return ScanStreamTransformer(
(Map<int, Future<ItemModel>> cache, int id, index) {
cache[id] = _newsRepository.fetchItem(id);
return cache;
},
<int, Future<ItemModel>>{},
);
}
dispose() {
//code
}
}
news_repository
class NewsRepository {
List<Source> sources = <Source>[
newsDbProvider,
NewsApiProvider(),
];
List<Cache> caches = <Cache>[
newsDbProvider,
];
Future<List<int>> fetchTopIds() async {
late List<int> ids;
Source source;
for (source in sources) {
ids = await source.fetchTopIds();
if (ids.isNotEmpty) {
break;
}
}
return ids;
}
Future<ItemModel> fetchItem(int id) async {
print('itemID to be fetched inside repo - $id');
ItemModel? item;
var source;
Cache cache;
for (source in sources) {
item = await source.fetchItem(id);
if (item != null) {
break;
}
}
for (cache in caches) {
if (cache != source){
cache.addItem(item!);
}
}
return item;
}
}
news_api_provider
class NewsApiProvider implements Source {
Client client = Client();
Future<List<int>> fetchTopIds() async {
final response = await client.get(Uri.parse('$_root/topstories.json'));
final parsedJsonIds = json.decode(response.body);
return parsedJsonIds.cast<int>();
}
Future<ItemModel> fetchItem(int id) async {
print('Inside API provider. Tryna fetch $id');
final response = await client.get(Uri.parse('$_root/item/$id.json'));
print('Status Code' + response.statusCode.toString());
print(response.body);
final parsedJsonItem = json.decode(response.body);
final itemModel = ItemModel.fromJson(parsedJsonItem);
return itemModel;
}
}
现在,有趣的部分是我确实在屏幕上看到“仍在加载项目 - itemID”,但它从未解决,就好像我的 FutureBuilder 从未收到任何数据一样。但是,在调试过程中,我能够看到我的 api 确实在工作,甚至 streamTransformer 中的缓存映射也被填充了。
我仍然无法理解为什么数据没有从 streamTransformer 流到我的 itemsOutput 流,它实际上负责显示这些数据。
我非常努力地让它工作,并检查了我的代码数百万次。如果您能帮我解决这个问题,我将不胜感激。提前致谢!
【问题讨论】:
-
仅供参考,写在代码语句之间的打印语句显示正确的结果。
标签: flutter dart stream bloc dart-async