如何根据以前下载的信息获取图像列表?

卡住溢出

我有2个rest API,一个用于数据,另一个用于图像。所以我做:

  1. 获取数据。
  2. 遍历数据。
  3. 在每个数据循环中,然后获取图像。

但是发生的是,所有加载的图像始终使用列表的最后一个图像。这是我的方法:

//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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

根据以前的 ID 获取记录 - Laravel

Rundeck:根据以前的用户输入填充下拉列表

根据以前的值添加到列表

根据同级值查询XML数据以获取信息

如何根据以前的过滤结果简化流搜索?

如何根据以前的连续行过滤出行?

如何根据以前的值更新MongoDB文档?

如何隐藏ngFor的div并根据以前的ngFor显示

如何使ValidateSet根据以前的参数显示不同的数据

如何根据以前的值显示选中的单选按钮?

根据以前的数据获取时间段内唯一值的数量

根据以前的记录更新列

根据以前的评分创建顺序排名

如何根据链接列表下载文件

如何根据下拉列表选择从Google表格中获取信息?

如何根据 API 获取的内容创建列表 + 详细信息页面

如何根据以前的值将当前级别的值设置为零

如何根据以前的状态在熊猫数据框中创建一列?

如何根据以前和将来的值填充缺失或空值?

我如何根据以前的答案呈现下一个问题

如何根据以前的日期以编程方式对 R 中的日期进行子集化?

如何根据以前的类别在熊猫数据框中创建一个新类别?

如何更改已下载图标(PNG)上的“图像”标签信息?

如何从列表中获取信息

如何从gh页获取DRAT存档的下载统计信息/分析

如何根据下载的图像大小创建动态大小的行高?

从网址列表下载图像

如何Ajax调用数据以扩展表行以获取更多信息

根据以前的更新动态更新用户界面