How to get List from future list function in Dart - flutter

I'm creating an app that use assets_audio_player to play music from a json response that are generated from a php script. There is a Future list function that return an Audio list. Audio isn't a Widget so i can't use a FutureBuilder. How can i use the future list?
Future<List<Audio>> creaLista() async {
final response = await http.post(Uri.parse(url));
String responseBody = response.body;
dynamic jsonObject = json.decode(responseBody);
final convertedJsonObject = jsonObject.cast<Map<String, dynamic>>();
List<Song> list =
convertedJsonObject.map<Song>((json) => Song.fromJson(json)).toList();
List<Audio> audioList = list
.map<Audio>((json) => Audio.network(
urlSong + json.url,
metas: Metas(
title: json.title,
artist: json.artist,
album: json.album,
image: MetasImage.network(
urlImage + json.image,
),
),
))
.toList();
return audioList;
}
This is the Song class:
class Song {
String title;
String artist;
String album;
String image;
String genre;
String url;
Song(
{required this.title,
required this.artist,
required this.album,
required this.image,
required this.genre,
required this.url});
factory Song.fromJson(Map<String, dynamic> json) => Song(
title: json['title'],
artist: json['artist'],
album: json['album'],
image: json['image'],
genre: json['genre'],
url: json['url']);
}
This is the json response:
[{"title":"Mille","artist":"Fedez, Achille Lauro, Orietta Berti","album":"Singolo","image":"mille.jpg","genre":"pop","url":"mille.mp3"}]

You don't need the Future to return a Widget to use FutureBuilder. You can create widgets based on the returned results of the future. Here's an example that would display the just the artist, but it should give you the idea.
In general I would suggest creating a custom Widget that takes an Audio object and displays all of the Audio data how you would like.
FutureBuilder(
future: creaLista(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final audioList = snapshot.data as List<Audio>;
return ListView.builder(
itemCount: audioList.length,
itemBuilder: (context, index) {
return Text(audioList[index].artist);
});
} else if (snapshot.hasError) {
// handle error here
return Text('${snapshot.error}');
} else {
return CircularProgressIndicator(); // displays while loading data
}
},
)
This assumes your Audio class looks like this
class Audio {
String title, artist, album;
Audio(this.title, this.artist, this.album);
}
I'm sure its more complex than that but it should give you the idea.

Related

Flutter error: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List<dynamic>' in type cast

I am trying to fetch News data from an API in JSON format and display it in my app.
News Class:
class News {
final String title;
final String desc;
final String imgURL;
final String url;
News(
{required this.title,
required this.desc,
required this.imgURL,
required this.url});
factory News.fromJSON(Map<String, dynamic> json) {
return News(
title: json["title"],
desc: json["description"],
imgURL: json["image_url"],
url: json["url"]);
}
}
News object getter:
Future<List<News>>? futureData;
Future<List<News>> getNews() async {
final response = await http.get(Uri.parse(
'https://api.stockdata.org/v1/news/all?&filter_entities=true&language=en&api_token=api_token&countries=in'));
if (response.statusCode == 200) {
List jsonResponse = json.decode(response.body);
return jsonResponse.map((data) => News.fromJSON(data)).toList();
} else {
throw Exception('Unexpected error occurred!');
}
}
FutureBuilder to display in the app:
FutureBuilder<List<News>>(
future: futureData,
builder: (context, snapshot) {
if (snapshot.hasData) {
print(snapshot);
List<News> data = snapshot.requireData;
return ListView.builder(
itemCount: data.length,
itemBuilder: (BuildContext context, int index) {
return Container(),
);
});
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default show a loading spinner.
return Center(child: CircularProgressIndicator());
}),
I keep getting the error:
type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List' in type cast
The response you receive from the api is of JsonObject similar to map but in the code you are trying to parse it as a list check how it looks here
your News.fromJSON() is written such that its taking only one object where as the data you are getting is of array.
factory News.fromJSON(Map<String, dynamic> json) {
return News(
title: json["title"],
desc: json["description"],
imgURL: json["image_url"],
url: json["url"]);
}
Currently your model class can only take one object not a list.
you can go through this

Display data fetched from JSON API in app

I am developing a Stock app in which I have to display News related to the stocks. I made a News class for the same as well as a factory constructor to convert the data from json
class News {
final String title;
final String desc;
final String imgURL;
final String url;
News(
{required this.title,
required this.desc,
required this.imgURL,
required this.url});
factory News.fromJSON(Map<String, dynamic> json) {
final title = json["title"] as String;
final desc = json["description"] as String;
final imgUrl = json["image_url"] as String;
final url = json["url"] as String;
return News(title: title, desc: desc, imgURL: imgUrl, url: url);
}
}
I have made a method to fetch the data from the API:
Future getNews() async {
final response = await http.get(Uri.parse(
'https://api.stockdata.org/v1/news/all?&filter_entities=true&language=en&api_token=${api_token}&countries=${country}'));
if (response.statusCode == 200) {
final jsonResponse = json.decode(response.body);
return jsonResponse.map((data) => News.fromJSON(data));
} else {
throw Exception('Unexpected error occurred!');
}
}
I am having trouble understanding how I can display the data in my app. I tried using FutureBuilder but I can't seem to understand how it's working.
Any help would be appreciated!
For the FutureBuilder you can do it this way :
FutureBuilder(
future: getNews(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.hasData){
// Save your data in a variable
List<News> news = snapshot.data;
// Create a listview to show all of the news
return newsListView(news); //This is a list
} else {
return Center(
child: Container(
width: 300,
height: 290,
child: Center(child: Text("Error"))
)
);
}
}
),

The getter 'length' was called on null. Receiver: null Tried calling: length FutureBuilder with List

I keep getting the error mentioned above during runtime of my flutter app. Basically what I am trying to achieve is to fetch data from an api and display it in a form of a SliverList by using a FutureBuilder.
This was working perfectly fine until I changed my code for the list from FutureBuilder<List> to FutureBuilder<List> to make use of the class EntertainerEvent which has all the fields I need for display from the json file.
How can I resolve this because it seems like the contructor or the application itslef is not picking up the data when I make use of a custom class.
This is the code for the EntertainerEvent class:
class EntertainerEvent {
final int eventId;
final int entertainerId;
final int eventTypeId;
final int categoryId;
final String eventName;
final String description;
final String imagePoster;
final String location;
final DateTime startDate;
final DateTime endDate;
final double entreeFee;
const EntertainerEvent({required this.eventId, required this.entertainerId, required this.eventTypeId,
required this.categoryId, required this.eventName, required this.description, required this.imagePoster,
required this.location, required this.startDate, required this.endDate, required this.entreeFee});
factory EntertainerEvent.fromJson(Map<String, dynamic> event) {
return EntertainerEvent(
eventId: event['EventID'],
entertainerId: event['EntertainerID'],
eventTypeId: event['EventTypeID'],
categoryId: event['CategoryID'],
eventName: event['EventName'],
description: event['Description'],
imagePoster: event['ImagePoster'],
location: event['Location'],
startDate: event['StartDate'],
endDate: event['EndDate'],
entreeFee: event['EntryFee'],
);
}
}
Below is the code for fetching data from the api:
Future<List<EntertainerEvent>> fetchEvents() async {
var result = await http.get(Uri.parse(apiUrl));
if (result.statusCode == 200) {
var content = result.body;
var arr = json.decode(content) as List;
return arr.map((eve) => new EntertainerEvent.fromJson(eve)).toList();
} else {
print('Not loaded');
throw Exception('Unable to fetch data from the Rest API');
}
}
late Future<List<EntertainerEvent>> _fetchEvents;
#override
void initState() {
_fetchEvents = fetchEvents();
super.initState();
}
#override
Widget build(BuildContext context) {
return FutureBuilder<List<EntertainerEvent>>(
future: _fetchEvents,
builder: (BuildContext context, AsyncSnapshot snapshot) {
var childCount = 0;
if (snapshot.connectionState != ConnectionState.done) {
childCount = 1;
} else {
childCount = snapshot.data.length;
}
return SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
if (snapshot.hasData) {
List<EntertainerEvent> someData = snapshot.data;
print('data here');
//Do some stuff
}
}, childCount: childCount),
);
});
}
I do not know what exactly is it that I am missing because this code works if I use the type dynamic instead of the custom class EntertainerEvent.
Thank you all in advance!
Wrap it with hasData:
if(snapshot.hasData){
return SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
List<EntertainerEvent> someData = snapshot.data;
print('data here');
//Do some stuff
}, childCount: childCount),
);}
return CircularProgressIndicator();

How do I collect a loop through a list from http in JSON

I'm learning Flutter, but I've been a dev for a while now. I'm using one of my sites to make it headless, and trying to feed the data into my app.
I'm following the example: https://flutter.dev/docs/cookbook/networking/fetch-data
In this example, they fetch a single user. I'm a bit lost on how this would change if there were multiple users.
For example, if the data was structured more like:
{'users':[{'userId':1,'id':1,'title':'title1','body':'This is Body 1'},{'userId':2,'id':2,'title':'title2','body':'This is Body 2'}]
How could you capture that using the method in the tutorial? How could you loop through the list and display something simple like the title and bodies?
Using the example from the tutorial, you could do this:
class Users {
final List<Post> users;
Users({this.users});
factory Users.fromJson(Map<String, dynamic> json) {
List<Post> tempUsers = [];
for (int i = 0; i < json['users'].length; i++) {
Post post = Post.fromJson(json['users'][i]);
tempUsers.add(post);
}
return Users(users: tempUsers);
}
}
And this is the Post class from the tutorial:
class Post {
final int userId;
final int id;
final String title;
final String body;
Post({this.userId, this.id, this.title, this.body});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
userId: json['userId'],
id: json['id'],
title: json['title'],
body: json['body'],
);
}
}
To show a list of titles and bodies, you could change the FutureBuilder on the tutorial like this:
final Future<Users> users;
...
FutureBuilder<Users>(
future: users,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.users.length,
itemBuilder: (context, index) {
return Column(
children: <Widget>[
Text('Title: ${snapshot.data.users[index].title}'),
Text('Body: ${snapshot.data.users[index].body}'),
],
);
},
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
I recommend you this article to learn more about parsing JSON:
Parsing complex JSON in Flutter
Also, here you can find more information about how to do manual serialization and automated serialization:
JSON and serialization

Proper way to parse a Json into a list of Object in Flutter

After a Webservice call I get json data like this:
{myteam: [
{'id': '1', name: 'xy'},
{'id': '2', name: 'zx'},
{'id': '3', name: 'gh'}
]}
I have an class in Flutter:
class CardData {
int id;
String name;
CardData({this.id, this.name});
}
I parse the data into a CardData list the following way:
List<CardData> CardsList = [];
List cards = List();
I get the data:
Map<String, dynamic> map = await ws.getData();
Put into the list
cards = map['myteam'];
Then iterate the cards:
cards.forEach((f) {
CardsList.add(CardData(id: f['id'], name: f['name']));
}
I know, that this is not the best way, but working. Now please help me somebody, how can I make the proper solution for this task.
You could use a logic like this to parse your Json:
class _MyHomePageState extends State<MyHomePage> {
String jsonList = '{"myteam":[{"id":"1","name":"xy"},{"id": "2","name":"zx"},{"id":"3","name": "gh"}]}';
Future<List<CardData>> listOfItems() async {
var parse = json.decode(jsonList);
var data = parse['myteam'] as List;
var map = data.map<CardData>((json) => CardData.parseJson(json));
return map.toList();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
child: Center(
child: FutureBuilder<List<CardData>>(
future: listOfItems(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Text(snapshot.data[0].name);
} else {
return Text("Loading...");
}
},
),
),
),
);
}
}
class CardData {
String id;
String name;
CardData({this.id, this.name});
factory CardData.parseJson(Map<String, dynamic> json) {
return CardData(id: json['id'], name: json['name']);
}
}
Right now, your Json is using String for the ID (you should remove the quotes to make it an Integer). Also, you myteam Json array key doesn't have any quotes.
Your parse looks pretty good, just a minor changes that i can point out are maybe that the constructor of CardData doesn't need the optional parameters and you can have a named constructor to build Cards from json as https://dart.dev/guides/language/language-tour encourage :
CardData.fromJson(Map<String, String> json)
: id = json['id'],
name = json['name'];
Then use it when you get the data from the server :
cards.forEach((f) {
CardsList.add(CardData.fromJson(f));
}
The other thing is that if the entire response means something to your domain (the team section composed by card array) you should consider make a class to parse the entire data and avoid use :
cards = map['myteam'];