How can I fetch images from api into card widget in flutter? - flutter

I'm trying to fetch api images into the card widgets in flutter. I have services, model and photos_page class. I tried lot's of ways but still doesn't work.
final photoItem = snapshot.data[index].previewURL;
I think problem is that snapshot can't get data
that's my photos_page:
import 'dart:convert';
import 'package:abcde/services/photos_model.dart';
import 'package:abcde/services/photos_service.dart';
import 'package:abcde/widgets/card_widget.dart';
import 'package:flutter/material.dart';
class PhotosPage extends StatefulWidget {
PhotosPage({Key? key}) : super(key: key);
static const String pathId = 'Photos page';
#override
State<PhotosPage> createState() => _PhotosPageState();
}
class _PhotosPageState extends State<PhotosPage> {
PhotosService photosService = PhotosService();
#override
void initState() {
// TODO: implement initState
super.initState();
photosService.getPhotos();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Photos'),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(children: [
_getProductTypeList(),
]),
),
);
}
Widget _buildListItem(
BuildContext context, AsyncSnapshot<dynamic> snapshot, int index) {
final photoItem = snapshot.data[index].previewURL;
print('photoItem is $photoItem');
return photoCard(photoItem);
}
Widget _buildList(BuildContext context, AsyncSnapshot<dynamic> snapshot) {
var values = snapshot.data;
return ListView.builder(
// itemCount: snapshot.length,
itemBuilder: (context, index) {
return _buildListItem(context, snapshot, index);
},
);
/* return ListView(
children: snapshot!.map((data) => _buildListItem(context, data)).toList(),
);*/
}
//PhotosModel photosModel = PhotosModel();
Widget _getProductTypeList() {
return Expanded(
child: FutureBuilder(
future: photosService.getPhotos(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: LinearProgressIndicator(),
);
}
return _buildList(context, snapshot);
},
),
);
}
}
that's my model class:
class PhotosModel {
String previewURL;
PhotosModel({required this.previewURL});
/* factory PhotosModel.fromJson(Map<dynamic, dynamic> json) => PhotosModel(
previewURL: json['previewURL'] as String,
);
Map<String, dynamic> toJson() {
return <String, dynamic>{'previewURL': previewURL};
}*/
/* #override
String toString() {
return 'PhotosModel{url: $previewURL}';
}*/
/*factory PhotosModel.fromJson(Map<String, dynamic> json) {
return PhotosModel(url: json['url'] as String);
}*/
factory PhotosModel.fromJson(Map<dynamic, dynamic> json) =>
_commentFromJson(json);
Map<dynamic, dynamic> toJson() => photosModelToJson(this);
}
PhotosModel _commentFromJson(Map<dynamic, dynamic> json) {
return PhotosModel(
previewURL: json['previewURL'],
);
}
Map<dynamic, dynamic> photosModelToJson(PhotosModel instance) => <dynamic, dynamic>{
'previewURL': instance.previewURL,
};
and that's my service class. I make a list getPhotos() method but doesn't work anyway.
import 'dart:convert';
import 'package:abcde/services/photos_model.dart';
import 'package:http/http.dart';
const MY_API_KEY = '26711456-bde74f403cb42e77029bc1678';
const appUrl = 'https://pixabay.com/api/';
class PhotosService {
Future getData(String url) async {
print('Calling url: $url');
final response = await get(Uri.parse(url));
if (response.statusCode == 200) {
return response.body;
} else {
print(response.statusCode);
}
}
List<PhotosModel> dataList = [];
Future<List<PhotosModel>> getPhotos({String? query}) async {
final photosData = await getData(
'$appUrl?&key=$MY_API_KEY&q=$query');
var data =json.decode(photosData);
data.forEach((element) {
dataList.add(PhotosModel.fromJson(element));
});
print('this is photos data: $photosData');
return dataList;
}
}
that's the error it shows me
The following NoSuchMethodError was thrown building:
The method '[]' was called on null.
Receiver: null
Tried calling:
and that's my card widget
import 'package:flutter/material.dart';
Widget photoCard(String url) {
return Card(
child: Image(
image: NetworkImage(url),
),
);
}
for api I use this web-page:
https://pixabay.com/api/docs/#api_search_images
thank you very much in advance

Working Example
main.dart
===============
import 'package:demo_app/photo_page.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const PhotosPage(),
);
}
}
==============
photo_service.dart
====================
import 'dart:convert';
import 'package:http/http.dart';
const apiKey = '26711456-bde74f403cb42e77029bc1678';
const appUrl = 'https://pixabay.com/api/';
class PhotosService {
Future getData(String url) async {
print('Calling url: $url');
final response = await get(Uri.parse(url));
if (response.statusCode == 200) {
return response.body;
} else {
print(response.statusCode);
}
}
List<PhotosModel> dataList = [];
Future<List<PhotosModel>> getPhotos(String query) async {
final photosData = await getData('$appUrl?key=$apiKey&q=$query');
var data = json.decode(photosData);
var items = data["hits"];
items.forEach((element) {
dataList.add(PhotosModel.fromJson(element));
});
print('this is photos data: $photosData');
return dataList;
}
}
class PhotosModel {
String previewURL;
PhotosModel({required this.previewURL});
factory PhotosModel.fromJson(Map<dynamic, dynamic> json) =>
_commentFromJson(json);
Map<dynamic, dynamic> toJson() => photosModelToJson(this);
}
PhotosModel _commentFromJson(Map<dynamic, dynamic> json) {
return PhotosModel(
previewURL: json['previewURL'],
);
}
Map<dynamic, dynamic> photosModelToJson(PhotosModel instance) =>
<dynamic, dynamic>{
'previewURL': instance.previewURL,
};
=========================
photo_page.dart
=============
import 'package:demo_app/photo_service.dart';
import 'package:flutter/material.dart';
class PhotosPage extends StatefulWidget {
const PhotosPage({Key? key}) : super(key: key);
static const String pathId = 'Photos page';
#override
State<PhotosPage> createState() => _PhotosPageState();
}
class _PhotosPageState extends State<PhotosPage> {
PhotosService photosService = PhotosService();
#override
void initState() {
super.initState();
photosService.getPhotos("flower");
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Photos'),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(children: [
_getProductTypeList(),
]),
),
);
}
Widget _buildListItem(
BuildContext context, AsyncSnapshot<dynamic> snapshot, int index) {
final photoItem = snapshot.data[index].previewURL;
print('photoItem is $photoItem');
return photoCard(photoItem);
}
Widget _buildList(BuildContext context, AsyncSnapshot<dynamic> snapshot) {
var values = snapshot.data;
return ListView.builder(
itemCount: snapshot.hasData ? snapshot.data.length : 0,
itemBuilder: (context, index) {
return _buildListItem(context, snapshot, index);
},
);
}
Widget _getProductTypeList() {
return Expanded(
child: FutureBuilder(
future: photosService.getPhotos("flower"),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: LinearProgressIndicator(),
);
}
return _buildList(context, snapshot);
},
),
);
}
}
Widget photoCard(String url) {
return Card(
child: Image(
image: NetworkImage(url),
),
);
}

Related

Racing problem of async function in Flutter

I have a Flutter page that makes use of 2 data sources: one from API (Internet) and one from Shared Preferences. The API source has no problem, as I used FutureBuilder in the build() method. For the Shared Preferences, I have no idea how to apply another Future Builder (or should I add one more?). Here are the codes (I tried to simplify them):
Future<List<City>> fetchCities(http.Client client) async {
final response = await client
.get(Uri.parse('https://example.com/api/'));
return compute(parseCities, response.body);
}
List<City> parseCities(String responseBody) {
final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<City>((json) => City.fromJson(json)).toList();
}
class CityScreen extends StatelessWidget {
static const routeName = '/city';
const CityScreen({super.key, required this.title});
final String title;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: FutureBuilder<List<City>>(
future: fetchCities(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString()),
);
} else if (snapshot.hasData) {
return CityList(cities: snapshot.data!);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
)
);
}
}
class CityList extends StatefulWidget {
const CityList({super.key, required this.cities});
final List<City> cities;
#override
State<CityList> createState() => _CityListState();
}
class _CityListState extends State<CityList> {
List<String> completedMissionIDs = [];
#override
void initState() {
super.initState();
Player.loadMissionStatus().then((List<String> result) {
setState(() {
completedMissionIDs = result;
if (kDebugMode) {
print(completedMissionIDs);
}
});
});
}
#override
Widget build(BuildContext context) {
return ListView.builder(
padding: const EdgeInsets.all(16.0),
itemCount: widget.cities.length * 2,
itemBuilder: (context, i) {
if (i.isOdd) return const Divider();
final index = i ~/ 2;
double completedPercent = _calculateCompletionPercent(widget.cities[index].missionIDs, completedMissionIDs);
return ListTile(
leading: const Icon(Glyphicon.geo, color: Colors.blue),
title: Text(widget.cities[index].cityName),
trailing: Text('$completedPercent%'),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => MissionScreen(title: '${widget.cities[index].cityName} Missions', cityId: widget.cities[index].id),
)
);
},
);
},
);
}
double _calculateCompletionPercent<T>(List<T> cityMissionList, List<T> completedList) {
if(cityMissionList.isEmpty) {
return 0;
}
int completedCount = 0;
for (var element in completedList) {
if(cityMissionList.contains(element)) {
completedCount++;
}
}
if (kDebugMode) {
print('Completed: $completedCount, Total: ${cityMissionList.length}');
}
return completedCount / cityMissionList.length;
}
}
The problem is, the build function in the _CityListState loads faster than the Player.loadMissionStatus() method in the initState, which loads a List<int> from shared preferences.
The shared preferences are loaded in the midway of the ListTiles are generated, making the result of completedPercent inaccurate. How can I ask the ListTile to be built after the completedPercent has been built?
Thanks.
I would start by making CityList a StatelessWidget that accepts completedMissionIDs as a constructor parameter.
Your CityScreen widget can call both APIs and combine the results into a single Future. Pass the combined Future to your FutureBuilder. That way you can render the CityList once all of the data has arrived from both APIs.
I put together a demo below:
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(
home: CityScreen(title: 'City Screen'),
));
}
class CombinedResult {
final List<City> cities;
final List<int> status;
const CombinedResult({
required this.cities,
required this.status,
});
}
class City {
final String cityName;
final List<int> missionIDs;
const City(this.cityName, this.missionIDs);
}
class Player {
static Future<List<int>> loadMissionStatus() async {
await Future.delayed(const Duration(seconds: 1));
return [0, 3];
}
}
Future<List<City>> fetchCities() async {
await Future.delayed(const Duration(seconds: 2));
return const [
City('Chicago', [1, 2, 3, 4]),
City('Helsinki', [1, 2, 3, 4]),
City('Kathmandu', [0, 4]),
City('Seoul', [1, 2, 3]),
];
}
class CityScreen extends StatefulWidget {
const CityScreen({super.key, required this.title});
final String title;
#override
State<CityScreen> createState() => _CityScreenState();
}
class _CityScreenState extends State<CityScreen> {
late Future<CombinedResult> _future;
#override
void initState() {
super.initState();
_future = _fetchData();
}
Future<CombinedResult> _fetchData() async {
final cities = await fetchCities();
final status = await Player.loadMissionStatus();
return CombinedResult(cities: cities, status: status);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: FutureBuilder<CombinedResult>(
future: _future,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString()),
);
} else if (snapshot.hasData) {
return CityList(
cities: snapshot.data!.cities,
completedMissionIDs: snapshot.data!.status,
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
);
}
}
class CityList extends StatelessWidget {
const CityList({
super.key,
required this.cities,
required this.completedMissionIDs,
});
final List<City> cities;
final List<int> completedMissionIDs;
#override
Widget build(BuildContext context) {
return ListView.separated(
padding: const EdgeInsets.all(16.0),
itemCount: cities.length,
separatorBuilder: (context, i) => const Divider(),
itemBuilder: (context, i) => ListTile(
leading: const Icon(Icons.location_city, color: Colors.blue),
title: Text(cities[i].cityName),
trailing: Text(
'${_calculateCompletionPercent(cities[i].missionIDs, completedMissionIDs)}%'),
),
);
}
double _calculateCompletionPercent<T>(
List<T> cityMissionList, List<T> completedList) =>
completedList.where(cityMissionList.contains).length /
cityMissionList.length;
}
First of all I would separate the data layer from the presentation. Bloc would be one example.
To combine 2 Futures you could do something like
final multiApiResult = await Future.wait([
sharedPrefs.get(),
Player.loadMissionStatus()
])

NoSuchMethodError: 'cast' with dart language

i'm following flutter offical docs to parse JSON in the background with the rest api from themoviedb. I get this following error when trying to show the list of movies
the api link : https://api.themoviedb.org/3/trending/movie/week?api_key=$apiKey
json data
app.dart'
simplify main.dart and isolate parsing using compute
import 'dart:convert';
import 'package:flutter/material.dart';
import 'models/movie_response.dart';
import 'package:auth_request/api_key.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
Future<List<Movie>> fetchMovies(http.Client client) async {
final response = await client
.get(Uri.parse('https://api.themoviedb.org/3/trending/movie/week?api_key=$apiKey'));
// Use the compute funtion to run fetchMovies in a separate isolate
return compute(parseMovies, response.body);
}
// A function that converts a response body into a List<Movie>.
List<Movie> parseMovies(String responseBody) {
final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<Movie>((json) => Movie.fromJson(json)).toList();
}
class MovieApp extends StatefulWidget {
const MovieApp({super.key});
#override
MovieAppState createState() => MovieAppState();
}
class MovieAppState extends State<MovieApp> {
late Future<Movie> futureAlbum;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'MovieDB List',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text('MovieDB List'),
),
body: Center(
child: FutureBuilder<List<Movie>>(
future: fetchMovies(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('${snapshot.error}');
} else if (snapshot.hasData) {
return MoviesList(movies: snapshot.data!);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
),
),
);
}
}
//
class MoviesList extends StatelessWidget {
const MoviesList({super.key, required this.movies});
final List<Movie> movies;
#override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
itemBuilder: (context, index) {
return Image.network(movies[index].original_title);
},
);
}
}
movie.dart
Parse and convert the JSON into a list of movies with the help of map and factory
class Movie {
final String original_title;
final String overview;
final String poster_path;
final String release_date;
const Movie({
required this.original_title,
required this.overview,
required this.poster_path,
required this.release_date,
});
factory Movie.fromJson(Map<String, dynamic> json) {
return Movie(
original_title: json['original_title'],
overview: json['overview'],
poster_path: json['poster_path'],
release_date: json['release_date'],
);
}
}
change this:
final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
to
final parsed = jsonDecode(responseBody)['results'];

Flutter: Stream data from rest api using Cubit

The idea is to fetch data from api continuously and show this data in screen, without need to fetch manually, like that if someone else perform a change on server data this change will be shown without user refreshing action.
The implementation is done in Flutter BLoC (cubit).
I have already get a console print of data in the cubit but I can't get same data in the BlocBuilder neither in the BlocListener.
My code is:
//data_repository.dart
import 'dart:async';
import 'data.dart';
class DataRepository {
final DataApi dataApi;
List<Map<String, dynamic>> formatedData = [];
final _controller = StreamController<List<Map<String, dynamic>>>();
DataRepository(this.dataApi) {
getData();
}
Future<void> getData() async {
Timer.periodic(Duration(seconds: 5), (timer) async {
formatedData.clear();
Map<String, dynamic> res = await dataApi.getData();
List<dynamic> data = res['data'];
for (var el in data) {
formatedData.add({'id': el['id'], 'name': el['name']});
}
_controller.add(formatedData);
});
}
#override
Stream<List<Map<String, dynamic>>> data() async* {
yield* _controller.stream;
}
#override
void dispose() => _controller.close();
}
Blockquote
This code is Data Repository it get data and make it available via a StreamController named "_controller";
Here data is got and controller is working perfectly.
My Cubit State is like this:
//data_list_state.dart
class DataListState extends Equatable {
final List<Map<String, dynamic>> data;
DataListState(this.data);
#override
List<Object> get props => [data];
DataListState copyWith({
List<Map<String, dynamic>>? data,
}) {
return DataListState(
data ?? this.data,
);
}
}
When I print within copyWith() I get updated data;
My Cubit code:
//data_list_cubit.dart
class DataListCubit extends Cubit<DataListState> {
DataListCubit(this.dataRepository) : super(DataListState([])) {
loadList();
}
final DataRepository dataRepository;
loadList() {
dataRepository.data().listen((event) {
if (event.isNotEmpty) {
emit(state.copyWith(data: dataRepository.formatedData));
}
});
}
}
When I print in loadList() I get the updated data;
My Screen Code:
//home.dart
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(children: [
BlocListener<DataListCubit, DataListState>(
listener: (context, state) {
if (state.data.isNotEmpty) print(state.data[0].toString());
},
child: BlocBuilder<DataListCubit, DataListState>(
builder: (context, state) {
if (state.data.isNotEmpty) print(state.data[0].toString());
return ListView(
shrinkWrap: true,
children: [
for (Map<String, dynamic> ff in state.data)
ListTile(
title: Text(ff['name']),
leading: Text(ff['id'].toString()),
),
],
);
},
),
),
]),
);
}
}
When I console print here I don't get data just for the first time, and after every 5 secondes (described in my getData()) I get updated data in all my codes excepting in the home.
Can you tell me if my cubit implementation is right ?
What should I do to make it work ?
Thanks in advance
You must add the BlocProvider above the BlocListener or BlocBuilder in HomePage.
tip: Learn BlocListener vs BlocBuilder vs BlocConsumer. All three must be enclosed in BlocProvider to work
class MyHomePage extends StatelessWidget {
DataRepository dataRepository = DataRepository();
#override
Widget build(BuildContext context) {
return SafeArea(
child: BlocProvider<DataListCubit>(
create: (context) => DataListCubit(dataRepository),
child: Scaffold(
body: BlocBuilder<DataListCubit, DataListState>(
builder: (context, state) {
print(state.data);
if (state.data.isNotEmpty) {
return ListView(
shrinkWrap: true,
children: [
for (Map<String, dynamic> ff in state.data)
ListTile(
title: Text(ff['name']),
leading: Text(ff['id'].toString()),
),
],
);
} else {
return const Center(
child: Text('No Data'),
);
}
},
),
),
),
);
}
}
Your Cubit State should be like below as you don't require
Equitable for state management in Cubit implementation
class DataListState {
const DataListState(this.data);
final List<Map<String, dynamic>> data;
DataListState copyWith({
List<Map<String, dynamic>>? data,
}) {
return DataListState(
data ?? this.data,
);
}
}
Full code
In absence of DataApi, I have structured the whole working code with random data as in below :
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Demo',
theme: ThemeData(),
home: MyHomePage(),
// home: VibrateHomepage(),
);
}
}
class MyHomePage extends StatelessWidget {
DataRepository dataRepository = DataRepository();
#override
Widget build(BuildContext context) {
return SafeArea(
child: BlocProvider<DataListCubit>(
create: (context) => DataListCubit(dataRepository),
child: Scaffold(
body: BlocBuilder<DataListCubit, DataListState>(
builder: (context, state) {
print(state.data);
if (state.data.isNotEmpty) {
return ListView(
shrinkWrap: true,
children: [
for (Map<String, dynamic> ff in state.data)
ListTile(
title: Text(ff['name']),
leading: Text(ff['id'].toString()),
),
],
);
} else {
return const Center(
child: Text('No Data'),
);
}
},
),
),
),
);
}
}
class DataRepository {
DataRepository() {
getData();
}
DataApi dataApi = DataApi();
List<Map<String, dynamic>> formattedData = [];
final _controller = StreamController<List<Map<String, dynamic>>>();
Future<void> getData() async {
Timer.periodic(const Duration(seconds: 5), (timer) async {
Map<String, dynamic> el = dataApi.getNew();
formattedData.add({'id': el['id'], 'name': el['name']});
_controller.add(formattedData);
});
}
Stream<List<Map<String, dynamic>>> data() async* {
yield* _controller.stream;
}
void dispose() => _controller.close();
}
class DataApi {
var rng = Random();
getNew() {
var rnd = rng.nextInt(100);
return {
"id": rnd,
"name": "Person " + rnd.toString()
};
}
}
class DataListState {
const DataListState(this.data);
final List<Map<String, dynamic>> data;
DataListState copyWith({
List<Map<String, dynamic>>? data,
}) {
return DataListState(
data ?? this.data,
);
}
}
class DataListCubit extends Cubit<DataListState> {
DataListCubit(this.dataRepository) : super(DataListState([])) {
loadList();
}
final DataRepository dataRepository;
loadList() {
dataRepository.data().listen((event) {
if (event.isNotEmpty) {
emit(state.copyWith(data: dataRepository.formattedData));
}
});
}
}

FutureBuilder - How to iterate through a list of Futures

I want to fetch price data of trading pairs specified inpriceList from the public Binance API and create a dynamic List of Card widgets using API response.
I am failing at this step as the future argument of FutureBuilder does not accept the list of Futures : List<Future<PriceListItem>> pliList
Thank you.
My code:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
));
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class PriceListItem {
final String pair;
final String price;
PriceListItem({
required this.pair,
required this.price,
});
factory PriceListItem.fromJson(Map<String, dynamic> json) {
return PriceListItem(
pair: json['symbol'],
price: json['price'],
);
}
}
class _HomePageState extends State<HomePage> {
List<String> pairList = [
"USTBUSD",
"USTUSDT",
"USDCBUSD",
"USDCUSDT",
"BUSDUSDT",
"BTCBUSD",
"USTBTC",
"BTCUSDT",
"BTCUSDC",
];
late Future<PriceListItem> pli;
late List<Future<PriceListItem>> pliList;
Future<PriceListItem> fetchPrice(String ticker) async {
final response = await http.get(Uri.parse(
"https://api.binance.com/api/v3/ticker/price?symbol=$ticker"));
if (response.statusCode == 200) {
return PriceListItem.fromJson(jsonDecode(response.body));
} else {
throw Exception("Failed to fetch price data.");
}
}
#override
void initState() {
pliList = [];
for (int i = 0; i < pairList.length; i++) {
pli = fetchPrice(pairList[i]);
pliList.add(pli);
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("price tracker"),
),
body: Column(
children: [
FutureBuilder<PriceListItem>(
future: pliList, //The argument type 'List<Future<PriceListItem>>' can't be assigned to the parameter type 'Future<PriceListItem>?'.dartargument_type_not_assignable
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: 2,
physics: const ScrollPhysics(),
padding: const EdgeInsets.all(8),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return Card(
child: ListTile(
title: Text(snapshot.data!.price),
subtitle: Text(snapshot.data!.pair),
trailing: const Icon(Icons.currency_bitcoin),
onTap: () {},
),
);
},
);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
)
],
),
);
}
}
Do it like this this:
FutureBuilder<List<PriceListItem>>(
future: Future.wait(pliList),
builder: (context, snapshot) {
}
https://api.flutter.dev/flutter/dart-async/Future/wait.html

Flutter 'List<Post>' has no instance getter 'lenght'

I'm new to flutter. I am getting an error like this, can you help me?
I've been stuck in http for json for 5 days, the codes in the source don't work. :( L
It says list not entered but when I enter it does not accept it.
I don't know on which line the problem is, but I got a warning like.
"The following NoSuchMethodError was thrown building FutureBuilder(dirty, state: _FutureBuilderState#447cc):"
enter image description here
enter image description here
// To parse this JSON data, do
//
// final post = postFromJson(jsonString);
import 'dart:convert';
Post postFromJson(String str) => Post.fromJson(json.decode(str));
String postToJson(Post data) => json.encode(data.toJson());
class Post {
Post({
required this.userId,
required this.id,
required this.title,
required this.body,
});
int userId;
int id;
String title;
String body;
factory Post.fromJson(Map<String, dynamic> json) => Post(
userId: json["userId"],
id: json["id"],
title: json["title"],
body: json["body"],
);
Map<String, dynamic> toJson() => {
"userId": userId,
"id": id,
"title": title,
"body": body,
};
}
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:json_http_place_holder/post.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Future getData = Future(() => null);
var con = Uri.parse("https://jsonplaceholder.typicode.com/posts");
Future<List<Post>> fetchPost() async {
List<Post> result = <Post>[];
final response = await http.get(con);
if (response.statusCode == 200) {
List listPost = jsonDecode(response.body);
for (int i = 0; i < listPost.length; i++) {
Post item = Post.fromJson(listPost[i]);
result.add(item);
}
}
return result;
}
#override
void initState() {
// TODO: implement initState
super.initState();
getData = fetchPost();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter HTTP json',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: FutureBuilder(
future: getData,
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
} else if (snapshot.connectionState == ConnectionState.none) {
return const Center(
child: Text("Bir hata meydana geldi"),
);
} else if (snapshot.connectionState == ConnectionState.done) {
return ListView.separated(itemBuilder: (context,index){
return ListTile(
leading: Icon(Icons.local_post_office),
title: Text(snapshot.data[index].title),
subtitle: Text(snapshot.data[index].body),
);
},separatorBuilder: (context,index)=>Divider(),
itemCount: snapshot.data.lenght,
);
}
//var d =jsonDecode(snapshot.data.body);
return Container();
},
),
),
);
}
}
You did not spell length well.
The error tells No such method on list lenght
The correct spelling for getting the method is .length
Change
itemCount: snapshot.data.lenght,
to
itemCount: snapshot.data.length,
In your main.dart,
FutureBuilder => separatorBuilder =>
itemCount: snapshot.data.lenght,
Change the itemCount from that to :
itemCount: snapshot.data.length,