流不重建小部件
Posted
技术标签:
【中文标题】流不重建小部件【英文标题】:Stream not rebuilding the widget 【发布时间】: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 流,它实际上负责显示这些数据。
我非常努力地让它工作,并检查了我的代码数百万次。如果您能帮我解决这个问题,我将不胜感激。提前致谢!
【问题讨论】:
仅供参考,写在代码语句之间的打印语句显示正确的结果。 【参考方案1】:好的。所以看起来 - 虽然 api 正在为***帖子发送一些 id,但是当我们通过 api 获取它们时这些 id 不存在(使用 fetchItem 方法)。因此,ItemModel 无法处理导致错误的此类请求。
我就是这样解决的->
ItemModel.fromJson(Map<String, dynamic> parsedJson)
: id = parsedJson['id'] ?? 0,
deleted = parsedJson['deleted'] ?? false,
type = parsedJson['type'] ?? '',
by = parsedJson['by'] ?? '',
time = parsedJson['time'] ?? 0,
text = parsedJson['text'] ?? '',
dead = parsedJson['dead'] ?? false,
parent = parsedJson['parent'] ?? 0,
kids = parsedJson['kids'] ?? [],
url = parsedJson['url'] ?? '',
score = parsedJson['score'] ?? 0,
title = parsedJson['title'] ?? 'Did not find',
descendants = parsedJson['descendants'] ?? 0;
【讨论】:
以上是关于流不重建小部件的主要内容,如果未能解决你的问题,请参考以下文章
如何创建自定义颤振 sdk 小部件,重建颤振和使用新的小部件