FutureBuilder не отображает элемент списка новостей.

Вопрос или проблема

Я пытаюсь отобразить полученные элементы через плитку списка новостей в своем приложении, но, похоже, данные не отображаются. Все еще стоит на “Потоки все еще загружаются”, и я не знаю, что происходит. Поэтому я представлю все соответствующие классы.

Это блок историй и класс поставщика историй.

import 'package:flutter/material.dart';
import 'package:new_flutter/src/blocs/stories_bloc.dart';

export 'stories_bloc.dart';

class StoriesProvider extends InheritedWidget {
  final StoriesBloc bloc;

  StoriesProvider({required Key super.key, required super.child})
      : bloc = StoriesBloc();

  @override
  bool updateShouldNotify(oldWidget) => true;

  static StoriesBloc of(BuildContext context) {
    final StoriesProvider? provider =
        context.dependOnInheritedWidgetOfExactType<StoriesProvider>();
    if (provider == null) {
      throw FlutterError('StoriesProvider не найден в дереве виджетов');
    }
    return provider.bloc;

    // return (context.dependOnInheritedWidgetOfExactType(aspect: StoriesProvider)
    //         as StoriesProvider)
    //     .bloc;
  }
}

Класс Stories_bloc:

import 'package:new_flutter/src/resources/repository.dart';
import 'package:rxdart/rxdart.dart';

import '../models/item_model.dart';

class StoriesBloc {
  final Repository _repository = Repository();
  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 _repository.fetchTopIds();
    _topIds.sink.add(ids);
  }

  _itemsTransformer() {
    return ScanStreamTransformer(
      (Map<int, Future<ItemModel?>> cache, int id, _) {
        cache[id] = _repository.fetchItems(id);
        return cache;
      },
      <int, Future<ItemModel>>{},
    );
  }
}

Теперь я покажу вам классы списка новостей и плитки списка новостей соответственно:

Это класс плитки списка новостей:

import 'package:flutter/material.dart';
import 'package:new_flutter/src/blocs/stories_provider_bloc.dart';
import 'package:new_flutter/src/models/item_model.dart';

class NewsListTile extends StatelessWidget {
  final int? itemId;

  const NewsListTile({super.key, this.itemId});

  @override
  Widget build(BuildContext context) {
    final bloc = StoriesProvider.of(context);
    return StreamBuilder(
        stream: bloc.items,
        builder:
            (context, AsyncSnapshot<Map<int, Future<ItemModel?>>> snapshot) {
          if (!snapshot.hasData) {
            return Text('Потоки все еще загружаются');
          }
          return FutureBuilder(
            future: snapshot.data![itemId],
            builder: (context, AsyncSnapshot<ItemModel?> itemSnapshot) {
              if (!itemSnapshot.hasData) {
                return Text('Элемент $itemId все еще загружается');
              }
              return Text(itemSnapshot.data!.title);
            },
          );
        });
  }
}

А это класс списка новостей, соответственно:

import 'package:flutter/material.dart';
import 'package:new_flutter/src/blocs/stories_provider_bloc.dart';
import 'package:new_flutter/src/widgets/news_list_tile.dart';

class NewsList extends StatelessWidget {
  const NewsList({super.key});

  @override
  Widget build(BuildContext context) {
    final bloc = StoriesProvider.of(context);

    ///Это плохо!!! не делай этого.
    ///Временно
    bloc.fetchTopIds();

    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        backgroundColor: Colors.blue,
        elevation: 5,
        title: const Text(
          'Лучшие новости',
          style: TextStyle(
            color: Colors.white,
          ),
        ),
      ),
      body: buildList(bloc),
    );
  }

  Widget buildList(StoriesBloc bloc) {
    return StreamBuilder(
      stream: bloc.topIds,
      builder: (context, AsyncSnapshot<List<int>> snapshot) {
        if (!snapshot.hasData) {
          return Center(
            child: CircularProgressIndicator(
              color: Colors.blue,
            ),
          );
        }

        return ListView.builder(
          itemCount: snapshot.data!.length,
          itemBuilder: (context, int index) {
            bloc.fetchItem(snapshot.data![index]);

            return NewsListTile(
              itemId: snapshot.data![index],
            );
          },
        );
      },
    );
  }
}

Это то, что отображается независимо от всего

Ответ или решение

Решение проблемы: FutureBuilder не отображает элемент списка новостей

Приветствую вас! Ваша проблема связана с тем, что элементы списка новостей в вашем приложении на Flutter не отображаются. Вместо этого пользователь видит сообщение "Streams still loading". Давайте разберемся в этом вопросе, анализируя ваш код и описывая возможные причины возникновения проблемы.

1. Понимание архитектуры приложения

Ваша архитектура приложения основана на паттерне BLoC (Business Logic Component), который позволяет эффективно управлять состоянием. Ваша структура классов, включающая StoriesProvider, StoriesBloc, NewsListTile и NewsList, выглядит хорошо. Однако необходимо убедиться, что потоки данных правильно обрабатываются и выводят ожидаемые результаты.

2. Проблемы с потоками данных

Ваша первоочередная задача — убедиться, что данные действительно загружаются и потоки данных функционируют должным образом. Рассмотрим несколько аспектов:

  • Метод fetchTopIds() в классе StoriesBloc: он должен заполнять поток topIds. Убедитесь, что вы вызываете его именно в момент инициализации вашего списка (что вы, кажется, уже делаете в NewsList), и что метод работает корректно.

  • Проверка данных: В вашем NewsList, после вызова fetchTopIds(), данные в стриме могут еще не успеть загрузиться, и это может привести к тому, что в StreamBuilder для topIds будет выводиться индикатор загрузки. Убедитесь, что метод fetchTopIds() фактически получает данные из репозитория.

3. Взаимодействие с FutureBuilder

В классе NewsListTile вы используете FutureBuilder, чтобы обработать данные, полученные в StreamBuilder. Убедитесь в следующем:

  • В FutureBuilder у вас указано future: snapshot.data![itemId]. В этом месте необходимо удостовериться, что itemId корректен, так как если он будет равен null или не будет существовать в fetched map, вы получите ошибку.

  • Также, убедитесь, что ваше отображение элемента списка работает правильно. Текущий код в FutureBuilder ожидает данные, и если они не приходят из-за незагруженного потока, вы получите сообщение об ошибке.

4. Возможные решения

  • Проверка методов репозитория: Убедитесь, что ваш метод fetchItems(id) возвращает данные. Для этого можно добавить логи, чтобы проверить, вызывается ли этот метод и возвращает ли он ожидаемые данные.

  • Обработка вопросов инициализации: Поскольку данные в BLoC загружаются асинхронно, убедитесь, что вы должным образом обрабатываете ситуации с "пустыми" данными. В текущий момент стоит добавить обработку для случая, если snapshot.data оказывается пустым в FutureBuilder.

Пример кода для улучшения обработки ошибок:

if (snapshot.data == null || !snapshot.data!.containsKey(itemId)) {
    return Text('Item not found');
}
  • Логирование этапов загрузки: Вставьте логи в ключевые точки вашего кода, чтобы понимать, какая часть не работает, и где именно ваш поток данных останавливается.

Заключение

Следуя приведенным выше шагам, вы сможете идентифицировать и устранить проблемы с отображением списка новостей. Не забудьте детально проверять все потоки данных и их инициализацию. Если проблемы останутся, используйте инструменты отладки Flutter для более глубокого анализа состояния потоков. Удачи в решении вашей задачи!

Оцените материал
Добавить комментарий

Капча загружается...