我有2个rest API,一个用于数据,另一个用于图像。所以我做:
但是发生的是,所有加载的图像始终使用列表的最后一个图像。这是我的方法:
//this is the list fetch
return
StreamBuilder(
stream: myBloc.myList,
builder: (context, AsyncSnapshot<List<Result>> snapshot){
if (snapshot.hasData) {
//build the list
return buildList(snapshot);
} else if (snapshot.hasError) {
return Text(snapshot.error.toString());
}
return Center(child: CircularProgressIndicator());
},
);
Widget buildList(AsyncSnapshot<List<Result>> snapshot) {
return GridView.builder(
itemCount: snapshot.data.length,
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 4),
itemBuilder: (BuildContext context, int index) {
//fetch the image
myBloc.fetchImageById(snapshot.data[index].Id.toString());
return
StreamBuilder(
stream: myBloc.imageById,
builder: (context, AsyncSnapshot<dynamic> snapshotImg){
if (snapshotImg.hasData) {
return
MyPlaceholder(
imageProvider: snapshotImg.data,
title: snapshot.data[index].name,
);
} else if (snapshotImg.hasError) {
return
MyPlaceholder(
imageProvider: null,
title: snapshot.data[index].name,
);
}
return Center(child: CircularProgressIndicator());
},
);
});
}
这是我的BLoC课程:
class MyBloc {
final _repository = MyRepository();
final _fetcher = PublishSubject<List<Result>>();
final _fetcherImage = PublishSubject<dynamic>();
Observable<List<Result>> get myList => _fetcher.stream;
Observable<dynamic> get myImageById => _fetcherImage.stream;
fetchResultList() async {
List<Result> result = await _repository.fetchMyList();
_fetcher.sink.add(result);
}
fetchImageById(String _id) async {
dynamic imgBinary = await _repository.fetchImageById(_id);
_fetcherImage.sink.add(imgBinary);
}
dispose() {
_fetcher.close();
_fetcherImage.close();
}
}
final categoryBloc = CategoryBloc();
我想念了吗?不可能在另一个集团内部拥有可观测集团?
但是发生的是所有加载的图像始终是列表的最后一个图像。
您的BLoC中的图像只有一个流,因此GridView行中的所有相应StreamBuilder都将仅使用快照中的最后一个值进行更新(并且最终得到最后一个图像)。
如果确定只有几个要显示在GridView中的图像,则可以使fetchImageById()方法为该特定图像创建一个流,保留对其的引用,然后将其返回。然后,您可以将返回的流传递给StreamBuilder而不是myBloc.imageById行,这样,您的行StreamBuilders将具有不同的数据源。加载图片后,您可以将其添加到该特定流中(基于ID),并且该行将仅使用该特定数据进行更新。一些代码:
//fetch the image
Observable<dynamic> imageStream = myBloc.fetchImageById(snapshot.data[index].Id.toString());
return StreamBuilder(
stream: imageStream,
builder: (context, AsyncSnapshot<dynamic> snapshotImg){
// rest of code
在您的BLoC中,您将拥有:
Map<String, PublishSubject<dynamic>> _backingImageStreams = HashMap()
Observable<dynamic> fetchImageById(String _id) {
PublishSubject<dynamic> backingImgStream = _backingImageStreams[id];
if (backingImgStream == null) {
backingImgStream = PublishSubject<dynamic>();
_backingImageStreams[id] = backingImgStream;
}
// i'm assuming that repository.fetchImageById() returns a Future ?!
_repository.fetchImageById(_id).then((){
_fetcherImage.sink.add(imgBinary);
});
return _fetcherImage.stream;
}
在更一般的情况下,我认为您需要从StreamBuilder中为FutureBuilder更改代码。在小部件中,您将拥有:
Widget buildList(AsyncSnapshot<List<Result>> snapshot) {
// ...
itemBuilder: (BuildContext context, int index) {
//fetch the image
Future<dynamic> imageFuture = myBloc.fetchImageById(snapshot.data[index].Id.toString());
return FutureBuilder(
future: imageFuture,
builder: (context, AsyncSnapshot<dynamic> snapshotImg){
// rest of your current code
然后,您需要更改BLoC方法fetchImageById()。在处理图像时,您将需要实现某种类型的缓存,以便提高效率:
BLoC代码:
class MyBloc {
// remove the imageId observable
// A primitive and silly cache. This will only make sure we don't make extra
// requests for images if we already have the image data, BUT if the user
// scrolls the entire GridView we will also have in memory all the image data.
// This should be replaced with some sort of disk based cache or something
// that limits the amount of memory the cache uses.
final Map<String, dynamic> cache = HashMap();
FutureOr<dynamic> fetchImageById(String _id) async {
// atempt to find the image in the cache, maybe we already downloaded it
dynamic image = cache[id];
// if we found an image for this id then we can simply return it
if (image != null) {
return image;
} else {
// this is the first time we fetch the image, or the image was previously disposed from the cache and we need to get it
dynamic image = // your code to fetch the image
// put the image in the cache so we have it for future requests
cache[id] = image;
// return the downloaded image, you could also return the Future of the fetch request but you need to add it to the cache
return image;
}
}
如果您只想向用户显示图像,则只需使fetchImageById()从图像获取请求中返回将来的内容即可(但是每次构建窗口小部件时都会发出获取请求)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句