Flutter не может вызывать вложенный json API

#json #flutter #api #flutter-getx

#json #трепетать #API #флаттер-геткс

Вопрос:

Я все еще новичок в разработке flutter и недавно пытался вызвать API. Мне удалось сделать это, не помещая данные в модель, и это сработало нормально. Проблема в том, когда я пытаюсь сериализовать данные. Я создал модель, используя app.quicktype.io. и я не уверен, как это назвать в моем файле представлений.

В проекте используется Getx.

Менеджер API

 import 'package:api_test_2/models/event.dart'; import 'package:http/http.dart' as http;   class ApiManager {  static var client = http.Client();    // Future as lt;Listlt;Eventgt;gt; maybe ?   static Futurelt;Event?gt; fetchEvents() async {  var response = await client.get(Uri.parse(  'https://xposure.ae/wp-json/wp/auditorium/v1/events'));  if (response.statusCode == 200) {  var jsonString = response.body;  print(jsonString);  return eventFromJson(jsonString);  } else {  //show error message  return null;  }  } }  

Модель событий

 // To parse this JSON data, do // // final event = eventFromJson(jsonString);  import 'package:meta/meta.dart'; import 'dart:convert';  Event eventFromJson(String str) =gt; Event.fromJson(json.decode(str));  String eventToJson(Event data) =gt; json.encode(data.toJson());  class Event {  Event({  required this.data,  });   Listlt;Datumgt;? data;   factory Event.fromJson(Maplt;String, dynamicgt; json) =gt; Event(  data: json["data"] == null ? null : Listlt;Datumgt;.from(json["data"].map((x) =gt; Datum.fromJson(x))),  );    //null check added after data   Maplt;String, dynamicgt; toJson() =gt; {  "data": data == null ? null : Listlt;dynamicgt;.from(data!.map((x) =gt; x.toJson())),  }; }  class Datum {  Datum({  required this.eventtitle,  required this.description,  required this.eventImage,  required this.speaker,  required this.datetime,  required this.location,  });   String? eventtitle;  String description;  String? eventImage;  Speaker? speaker;  String? datetime;  Location? location;   factory Datum.fromJson(Maplt;String, dynamicgt; json) =gt; Datum(  eventtitle: json["Eventtitle"] == null ? null : json["Eventtitle"],  description: json["Description"] == null ? null : json["Description"],  eventImage: json["event_image"] == null ? null : json["event_image"],  speaker: json["Speaker"] == null ? null : Speaker.fromJson(json["Speaker"]),  datetime: json["datetime"] == null ? null : json["datetime"],  location: json["Location"] == null ? null : Location.fromJson(json["Location"]),  );   Maplt;String, dynamicgt; toJson() =gt; {  "Eventtitle": eventtitle == null ? null : eventtitle,  "Description": description == null ? null : description,  "event_image": eventImage == null ? null : eventImage,  "Speaker": speaker == null ? null : speaker!.toJson(),  "datetime": datetime == null ? null : datetime,  "Location": location == null ? null : location!.toJson(),  }; }  class Location {  Location({  required this.venue,  required this.address,  });   Venue? venue;  Address? address;   factory Location.fromJson(Maplt;String, dynamicgt; json) =gt; Location(  venue: json["venue"] == null ? null : venueValues.map[json["venue"]],  address: json["address"] == null ? null : addressValues.map[json["address"]],  );   //added null checks after reverse   Maplt;String, dynamicgt; toJson() =gt; {  "venue": venue == null ? null : venueValues.reverse![venue],  "address": address == null ? null : addressValues.reverse![address],  }; }  enum Address { SHARJAH_BR_SHARJAH_BR_61110_BR_UNITED_ARAB_EMIRATES }  final addressValues = EnumValues({  "Sharjahlt;/brgt;Sharjah,lt;/brgt;61110,lt;/brgt;United Arab Emirates": Address.SHARJAH_BR_SHARJAH_BR_61110_BR_UNITED_ARAB_EMIRATES });  enum Venue { XPOSURE_INTERNATIONAL_PHOTOGRAPHY_FESTIVAL }  final venueValues = EnumValues({  "Xposure International Photography Festival": Venue.XPOSURE_INTERNATIONAL_PHOTOGRAPHY_FESTIVAL });  class Speaker {  Speaker({  required this.speakername,  required this.link,  });   String speakername;  String link;   factory Speaker.fromJson(Maplt;String, dynamicgt; json) =gt; Speaker(  speakername: json["speakername"] == null ? null : json["speakername"],  link: json["link"] == null ? null : json["link"],  );   Maplt;String, dynamicgt; toJson() =gt; {  "speakername": speakername == null ? null : speakername,  "link": link == null ? null : link,  }; }  class EnumValueslt;Tgt; {  Maplt;String, Tgt; map;  Maplt;T, Stringgt;? reverseMap;   EnumValues(this.map);   Maplt;T, Stringgt;? get reverse {  if (reverseMap == null) {  reverseMap = map.map((k, v) =gt; new MapEntry(v, k));  }  return reverseMap;  } }  

Controller

 import 'package:api_test_2/models/event.dart'; import 'package:api_test_2/services/api_manager.dart'; import 'package:get/state_manager.dart';   class EventController extends GetxController {  var isLoading = true.obs;  // var eventList = Listlt;Eventgt;().obs;  var eventList = lt;Eventgt;[].obs;   @override  void onInit() {  fetchEvents();  super.onInit();  }   void fetchEvents() async {  try {  isLoading(true);  var events = await ApiManager.fetchEvents();  if (events != null) {   // added cast as Listlt;Eventgt;  eventList.value = events as Listlt;Eventgt;;  }  } finally {  isLoading(false);  }  } }  

Main view

 import 'package:api_test_2/controllers/event_controller.dart'; import 'package:api_test_2/views/event_tile.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:get/get.dart'; import 'package:get/instance_manager.dart';  class HomePage extends StatelessWidget {  final EventController eventController = Get.put(EventController());   @override  Widget build(BuildContext context) {  return Scaffold(  appBar: AppBar(  elevation: 0,  leading: const Icon(  Icons.arrow_back_ios,  ),  actions: [  IconButton(  icon: const Icon(  Icons.shopping_cart,  ),  onPressed: () {},  )  ],  ),  body: Column(  children: [  Padding(  padding: const EdgeInsets.all(16),  child: Row(  children: [  const Expanded(  child: Text(  'ShopX',  style: TextStyle(  fontFamily: 'avenir',  fontSize: 32,  fontWeight: FontWeight.w900),  ),  ),  IconButton(  icon: const Icon(Icons.view_list_rounded), onPressed: () {}),  IconButton(icon: const Icon(Icons.grid_view), onPressed: () {}),  ],  ),  ),  Expanded(  child: Obx(() {  if (eventController.isLoading.value)  return Center(child: CircularProgressIndicator());  else {  return StaggeredGridView.countBuilder(  crossAxisCount: 1,  itemCount: eventController.eventList.length,  crossAxisSpacing: 16,  mainAxisSpacing: 16,  itemBuilder: (context, index) {  return EventTile(eventController.eventList[index]);  },  staggeredTileBuilder: (index) =gt; StaggeredTile.fit(1),  );  }  }),  )  ],  ),  );  } }  

Плитка событий

 import 'package:api_test_2/models/event.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart';   class EventTile extends StatelessWidget {  final Event event;  const EventTile(this.event);   @override  Widget build(BuildContext context) {  return Card(  elevation: 2,  child: Padding(  padding: const EdgeInsets.all(8.0),  child: Column(  crossAxisAlignment: CrossAxisAlignment.start,  children: [  // Text(   // ),  ],  ),  ),  );  } }  

Я думаю, что делаю что-то не так с преобразованием в список или карту, но я не уверен, находится ли это в моем классе API manager или в самой модели событий. Если бы кто-нибудь мог помочь, я был бы так благодарен.

Комментарии:

1. Вы извлекаете данные из API и отображаете их в виджетах?

2. Да, я могу извлекать данные и отображать их в виджетах. Проблема в том, что я пытаюсь поместить его в класс модели, а затем вызвать модель в виджет.

Ответ №1:

Ваш фактический список событий находится внутри data свойства вашей модели. Поэтому ваш контроллер должен быть:

 class EventController extends GetxController {  final isLoading = true.obs;  final event = Rxnlt;Eventgt;();   @override  void onInit() async{  await fetchEvents();  super.onInit();  }   void fetchEvents() async {  try {  isLoading(true);  var response = await ApiManager.fetchEvents();  if (response != null) {  event.value = response;  }  } finally {  isLoading(false);  }  } }  

И твой StaggeredGridView :

 return StaggeredGridView.countBuilder(  crossAxisCount: 1,  itemCount: eventController.event.value.data.length,  crossAxisSpacing: 16,  mainAxisSpacing: 16,  itemBuilder: (context, index) {  return EventTile(eventController.event.value.data[index]);  },  staggeredTileBuilder: (index) =gt; StaggeredTile.fit(1),  );  

И, наконец, ваш EventTile :

 class EventTile extends StatelessWidget {  final Datum datum;  const EventTile(this.datum);   @override  Widget build(BuildContext context) {  return Card(  elevation: 2,  child: Padding(  padding: const EdgeInsets.all(8.0),  child: Column(  crossAxisAlignment: CrossAxisAlignment.start,  children: [  // Text(   // ),  ],  ),  ),  );  } }  

Комментарии:

1. Большое вам спасибо! Я целую вечность не мог этого понять.

2. Исправлено? Если это так, пожалуйста, примите это как ответ.

3. Да, сейчас это работает. Еще раз спасибо