тип Future ‹dynamic› не является подтипом типа Stream ‹dynamic›, получающим данные из Firebase.

Я получаю данные из Firebase Storage и Firestore, чтобы показать элементы в списке со значком (если элемент является файлом) или изображением (если это изображение). Проблема в том, что если я получаю все изображения за один раз, он загружает не все .. Он загружается максимум 20 и вылетает из-за утечки памяти. Итак, моя идея состоит в том, чтобы создать список, который будет содержать 10 элементов по времени, и когда пользователь прокручивает вниз до конца результатов, он загружает еще 10 элементов, а затем. Но я использовал Future Builder, и с его помощью я не могу обновлять список, когда мне нужно, и проблема сохраняется, поэтому теперь я пытаюсь войти в поток и показать с помощью StreamBuilder, чтобы иметь возможность динамически обновлять список.

это мой контроллер:

loadList(String submenu, [int limit]) async {
    var parts = submenu.split('/');
    var pathSlashless = parts[0].trim();
    var subPathSlashless = parts.sublist(1).join('/').trim();

    var snapshot = await _storage.ref().child("/${submenu}");
    var retorno = await snapshot.listAll();
    List<ItemLab> conteudo = [];

    if(subPathSlashless.isEmpty || subPathSlashless == null){
      retorno.prefixes.forEach((element) {
        conteudo.add(
          ItemLab(
            tipo: 'PASTA',
            elemento: element,
          ),
        );
      });
    }

    for(int i = 0; i < retorno.items.length ; i++){
      var url = await retorno.items[i].getDownloadURL();
      conteudo.add(
        ItemLab(
          tipo: 'FILE',
          elemento: retorno.items[i],
          imageUrl: url,
        ),
      );

      if(limit != null){
        if(conteudo.length > limit){
          hasMore = true;
          return Stream.value(conteudo);
        }else{
          hasMore = false;
          print("less than 9");
        }
      }
    }

    try {
      if(subPathSlashless.isNotEmpty){
        print(subPathSlashless);
        List items;
        await databaseReference
            .collection("lab_${pathSlashless}_url")
            .snapshots().forEach((element) {
              element.docs.forEach((f) {
                if(f.data()['videos'] != null){
                    items == null ? items = f.data()['videos'] :
                    items.addAll(f.data()['videos']);
                  };
                  print("ITEMS :::: >>> ${items}");
              });
        });


        for(int i = 0; i < items.length; i ++){
          //print(items[i]);
          conteudo.add(
            ItemLab(
              tipo: 'VIDEO',
              elemento: null,
              video: items[i],
            ),
          );
        }

      }else{
        await databaseReference
            .collection("lab_${pathSlashless}_url")
            .snapshots().forEach((element) {
          element.docs.forEach((f) {
            if(f.data().isNotEmpty){
              print(f.data());
              if(f.data().keys.contains("videos")){
                conteudo.add(
                  ItemLab(
                      tipo: 'PASTA',
                      pastaVideo: findFolderName(f.reference.path)
                  ),
                );
              }else{
                conteudo.add(
                  ItemLab(
                    tipo: 'VIDEO',
                    elemento: null,
                    video: f.data(),
                  ),
                );
              }
            }
          });
        });
      }


    }catch(e){
      print(e);
    }

    pathSlashless = null;
    subPathSlashless = null;
    conteudo = checkDuplicateFolder(conteudo, submenu);
    return Stream.value(conteudo);
  }

И вот мой список:

return StreamBuilder(
      stream: ctrl.loadList(submenu),
      builder: (ctx, snapshot) {

Но если я запустил этот код, он выдает следующую ошибку:

тип "Future" не является подтипом типа "Stream"

Как я могу справиться с этим, чтобы иметь возможность динамически обновлять список, используя поток вместо Future


person armstrong    schedule 19.02.2021    source источник
comment
Это тот случай, когда вам нужно знать, что вы на самом деле пытаетесь сделать, чтобы знать, как ответить на свой вопрос. Метод, помеченный как async, должен возвращать Future, и вы пытаетесь передать его в StreamBuilder, которому требуется Stream. Но в каком направлении вам нужно двигаться, чтобы это исправить, зависит от того, что вы пытаетесь сделать. Если вам нужно вернуть Stream, используйте async*, но если вы действительно пытаетесь вернуть Future, используйте вместо этого FutureBuilder.   -  person Abion47    schedule 19.02.2021


Ответы (1)


Вы не можете ждать .snapshots (), поскольку он возвращает stream, вы можете изменить его, чтобы получить. Также узнайте больше о flutter firebase в реальном времени и обычном сценарии использования, ознакомьтесь с документацией по flutter fire

loadList(String submenu, [int limit]) async {
    var parts = submenu.split('/');
    var pathSlashless = parts[0].trim();
    var subPathSlashless = parts.sublist(1).join('/').trim();

    var snapshot = await _storage.ref().child("/${submenu}");
    var retorno = await snapshot.listAll();
    List<ItemLab> conteudo = [];

    if(subPathSlashless.isEmpty || subPathSlashless == null){
      retorno.prefixes.forEach((element) {
        conteudo.add(
          ItemLab(
            tipo: 'PASTA',
            elemento: element,
          ),
        );
      });
    }

    for(int i = 0; i < retorno.items.length ; i++){
      var url = await retorno.items[i].getDownloadURL();
      conteudo.add(
        ItemLab(
          tipo: 'FILE',
          elemento: retorno.items[i],
          imageUrl: url,
        ),
      );

      if(limit != null){
        if(conteudo.length > limit){
          hasMore = true;
          return Stream.value(conteudo);
        }else{
          hasMore = false;
          print("less than 9");
        }
      }
    }

    try {
      if(subPathSlashless.isNotEmpty){
        print(subPathSlashless);
        List items;
        (await databaseReference
            .collection("lab_${pathSlashless}_url")
            .get()).docs.forEach((f) {
                if(f.data()['videos'] != null){
                    items == null ? items = f.data()['videos'] :
                    items.addAll(f.data()['videos']);
                  };
                  print("ITEMS :::: >>> ${items}");
              });


        for(int i = 0; i < items.length; i ++){
          //print(items[i]);
          conteudo.add(
            ItemLab(
              tipo: 'VIDEO',
              elemento: null,
              video: items[i],
            ),
          );
        }

      }else{
        (await databaseReference
            .collection("lab_${pathSlashless}_url")
            .get()).docs.forEach((f) {
            if(f.data().isNotEmpty){
              print(f.data());
              if(f.data().keys.contains("videos")){
                conteudo.add(
                  ItemLab(
                      tipo: 'PASTA',
                      pastaVideo: findFolderName(f.reference.path)
                  ),
                );
              }else{
                conteudo.add(
                  ItemLab(
                    tipo: 'VIDEO',
                    elemento: null,
                    video: f.data(),
                  ),
                );
              }
            }
          });
      }


    }catch(e){
      print(e);
    }

    pathSlashless = null;
    subPathSlashless = null;
    conteudo = checkDuplicateFolder(conteudo, submenu);
    return conteudo;
  }

И список

return FutureBuilder(
      future: ctrl.loadList(submenu),
      builder: (ctx, snapshot) {
person dlohani    schedule 19.02.2021
comment
Но я хочу вернуть Stream, чтобы иметь возможность динамически изменять список ... Вы могли бы помочь? - person armstrong; 19.02.2021
comment
Проверьте комментарии, пожалуйста - person armstrong; 19.02.2021