Flutter получить элементы списка из результата API с шаблоном BloC

Я новичок в BloC Pattern. Я отправляю запрос в API погоды, и он возвращает результат JSON, как показано ниже. Как видите, результатом является массив объектов json

Я отформатировал его в модель погоды в моем классе ответа.

Класс погодной модели

class Weather {
  String date;
  String day;
  String icon;
  String description;
  String status;
  String degree;
  String min;
  String max;
  String night;
  String humidity;

  Weather({this.date, this.day, this.icon, this.description, this.status,
      this.degree, this.min, this.max, this.night, this.humidity});

  Weather.init(this.date, this.day, this.icon);

  factory Weather.fromJson(Map<String, dynamic> json){
    return Weather(
      date: json['date'] as String,
      day:  json['day'] as String,
      icon: json['icon'] as String,
      description: json['description'] as String,
      status: json['status'] as String,
      degree: json['degree'] as String,
      min: json['min'] as String,
      max: json['max'] as String,
      night: json['night'] as String,
      humidity: json['humidity'] as String,
    );
  }

Класс ответа

class WeatherResponse {
  bool success;
  String city;
  List<Weather> result;

  WeatherResponse({this.success, this.city, this.result});

  factory WeatherResponse.fromJson(Map<String, dynamic> json) {
    var weathersFromJson = json['result'] as List<dynamic>;
    List<Weather> weatherList = List<Weather>();
    weathersFromJson.forEach((element) {
      Weather weather = Weather.fromJson(element);
      weatherList.add(weather);
    });

    return WeatherResponse(
      success: json['success'] as bool,
      city:  json['city'] as String,
      result: weatherList
    );

  }
}

Блок погоды

enum WeatherEvent { getWeather, getDetails }

class WeatherBloc extends Bloc<WeatherEvent, Weather> {
  WeatherBloc(Weather initialState) : super(initialState);

  @override
  Stream<Weather> mapEventToState(WeatherEvent event) async*{
    switch (event) {
      case WeatherEvent.getWeather:
        WeatherRequest().fetchWeathers().then((weatherResponse) =>
          weatherResponse.result.forEach((element) {
            return element;
          })
        );
        break;

      case WeatherEvent.getDetails:
        break;
    }
  }
}

Я хочу использовать yield вместо элемента return, и когда приходят данные, я хочу отправить этот элемент результатов списка погоды в пользовательский интерфейс.

Конструктор блоков пользовательского интерфейса

 BlocBuilder<WeatherBloc, Weather>(
            builder: (context, result) {
              print(result.date);
              return (Text(result.date));
            },
          ),

Может я что-то упускаю. Когда я пишу
print(result.date); в свой класс Bloc, он печатает. Но в классе UI и BlocBuilder ничего нет. Когда я отлаживаю его, я вижу, что: после того, как строка возвращаемого элемента работает, он не переходит к BlocBuilder, потому что каждый из них продолжается. Но когда он закончится, он все равно не прыгнет. Может быть, моя архитектура или подход ошибочны. Также я открыт для предложений по этому поводу.

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


person burcus    schedule 30.07.2020    source источник
comment
как сказал @tayomi, вы должны расширить свой погодный блок блоком ‹WeatherEvent, WeatherState›. Не стесняйтесь просматривать мое репо, если вам нужна ссылка на использование блока   -  person kabayaba    schedule 30.07.2020


Ответы (1)


Вы не определили состояние своего Блока. Вы должны создать государство

class WeatherState
class WeatherLoaded extends WeatherState{
      final Weather weather;
  WeatherLoaded(this.weather);
}

Тогда ваш класс Bloc должен выглядеть так: WeatherEvent и WeatherState

class WeatherBloc extends Bloc<WeatherEvent, WeatherState> {
  WeatherBloc(Weather initialState) : super(initialState);

  @override
  Stream<Weather> mapEventToState(WeatherEvent event) async*{
    switch (event) {
      case WeatherEvent.getWeather:
        // Api call call that returns a weather object.
        final res = await WeatherRequest().fetchWeathers();
        yield WeatherLoaded(res);
        break;

      case WeatherEvent.getDetails:
        break;
    }
  }
}

Далее ваш Bloc Builder должен выглядеть так

         BlocBuilder<WeatherBloc, WeatherState>(
            builder: (context, WeatherState state) {
              if(state is WeatherLoaded) {
                return (Text(state.date));
              }
              
            },
          ),

Вы должны переписать вызов API, чтобы он возвращал объект Weather.

person Tayormi    schedule 30.07.2020
comment
Спасибо за ответ и объяснение. Это сработало. Также теперь я могу понять логику состояния. - person burcus; 12.08.2020
comment
Рад, что у вас сработало @burcus. Пожалуйста, подумайте о том, чтобы проголосовать за ответ, чтобы другие могли его найти. - person Tayormi; 14.08.2020