I want to get some data from a movie API but after I reload my screen, It gives me an error of bad state no element although I dont get any compilation error. Below is the method which i used to fetch the data from the api
Please NB: I am using the provider state management
Future<void> loadMovies() async {
const _apiKey = '*****************************';
const _readAccessToken =
'***************************************';
List<Movie> loadedTrendingMovies = [];
TMDB tmdbWithCustomLogs = TMDB(
ApiKeys(_apiKey, _readAccessToken),
logConfig: const ConfigLogger(
showLogs: true,
showErrorLogs: true,
),
);
try {
final trendingMoviesResponse = await tmdbWithCustomLogs.v3.trending
.getTrending() as Map<String, dynamic>;
final discoverMoviesResponse = await tmdbWithCustomLogs.v3.discover
.getMovies() as Map<String, dynamic>;
final trendingReults = trendingMoviesResponse['results'] as List;
for (var movieData in trendingReults) {
loadedTrendingMovies.add(Movie(
id: movieData['id'].toString(),
title: movieData['original_title'] ?? 'Loading...',
description: movieData['overview'] ?? 'Loading...',
rate: movieData['vote_average'],
releaseDate: movieData['release_date'],
imageUrl: movieData['poster_path'],
));
}
_trendingMovies = loadedTrendingMovies;
notifyListeners();
} catch (error) {
print(error);
rethrow;
}
print(_trendingMovies.last.title);
}
Also below is the future builder which listens to changes in my provider
FutureBuilder(
future: Provider.of<Movies>(context, listen: false).loadMovies(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
return Text(snapshot.error.toString()); //This error does not even appears on the screen as text but so that means, the code breaks before making it here.
} else {
return Consumer<Movies>(
builder: (context, movieData, _) => Swiper(
itemBuilder: (BuildContext context, i) {
return MovieContainer(
imageUrl: movieData.trendingMovies[i].imageUrl,
id: movieData.trendingMovies[i].id,
rate: movieData.trendingMovies[i].rate,
title: movieData.trendingMovies[i].title,
);
},
itemCount: movieData.trendingMovies.length,
viewportFraction: 0.25,
scale: 0.4,
),
);
}
}),
Related
I want to fetch data from api and showing on app screen but there nothing on screen but a circular progress indicator. if i try to print response.body on consol it works just fine and showing the body of data in consol but it not showing anything to app screen. weher is the problem of my code???
I try to change itemcount: snapshot.data?.length, but didnt do anything. if i want to print api data on consol it works fine. but not showing to screen.
class _MyHomePageState extends State<MyHomePage> {
List<ApiModel> apiModel = [];
final url = "https://newsapi.org/v2/top-headlines?country=us&category=sports&apiKey=bb66e3f0405944a58cb6853e55995bec";
Future<List<ApiModel>> getData() async {
final response = await http.get(Uri.parse(url));
var data = jsonDecode(response.body.toString());
if (response.statusCode == 200) {
for (Map<String, dynamic> index in data) {
apiModel.add(ApiModel.fromJson(index));
}
return apiModel;
} else {
return apiModel;
}
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: getData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: apiModel.length,
itemBuilder: (context, index){
return Container(
height: 200,
child: Column(
children: [
Text.rich(TextSpan(children: [
TextSpan(text: 'data'),
TextSpan(text: 'data'),
]))
],
),
);
});
}else{
return Center(child: CircularProgressIndicator(),);
}
});
}
}
Your data is not correctly mapped in you ApiModel because you mapping in wrong way so update your getData() with below code.
Future<ApiModel> getData() async {
try {
final response = await http.get(Uri.parse(url));
var data = jsonDecode(response.body.toString());
if (response.statusCode == 200) {
apiResposne = ApiModel.fromJson(data);
return apiResposne;
} else {
return apiResposne;
}
} catch (ex) {
return apiResposne;
}
}
Also you need to update FutureBuilder UI widget part to update data so replace below code.
FutureBuilder(
future: getData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: apiResposne.articles?.length ?? 0,
itemBuilder: (context, index) {
return SizedBox(
height: 200,
child: Column(
children: [
Text.rich(TextSpan(children: [
TextSpan(
text:
(apiResposne.articles?[index].author ?? "")),
TextSpan(
text: (apiResposne.articles?[index].publishedAt ??
"")),
]))
],
),
);
});
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
})
I have a StreamProvider here:
final secondTabProvider = StreamProvider((ref){
EmergencyContactsController contacts = EmergencyContactsController(currentUserID: ref.read(authProvider).currentUser!.uid);
return contacts.getUserEmergencyContacts();
});
And I call it in my build method like so:
_secondTab.when(
data: (data) {
if (!data.exists){
return Text("no data")
}
Map<String, dynamic doc = data.doc() as Map<String, dynamic>;
List conversations = doc['conversation'];
// Store the user profiles
List<EmergencyContactModel> users = [];
for (Map<String, dynamic> user in userConversations){
contacts.getContactInfo(
uid: user['userID']
).then((value){
if (value != null){
EmergencyContactModel contact = EmergencyContactModel.fromJson(value);
contact.messageID = value["id"] + ref.read(authProvider).currentUser!.uid;
users.add(contact);
}
});
}
return Listview.builder(
itemCount: users.length,
itemBuilder: (BuildContext context, int index) => Text(users[index]['name'])
);
},
error: (err, _){
return Text("Error")
},
loading: () => CircularProgressIndicator()
)
The contacts.getContactInfo() method is an async and I need it to execute before the loop continues to the next iteration, but it's not doing that. Any help would be largely appreciated.
I solved it. I converted the for loop into its own async function as seen below:
// Generate a list of users that the current user has had conversations with
userinfoGenerator(List userIDs) async {
// Get the user profiles
List<EmergencyContactModel> users = [];
for (Map<String, dynamic> user in userIDs){
Map<String, dynamic>? contactInfo = await contacts.getContactInfo(uid: user['userID']);
if (contactInfo != null){
EmergencyContactModel contact = EmergencyContactModel.fromJson(contactInfo);
contact.messageID = contactInfo["id"] + ref.read(authProvider).currentUser!.uid;
users.add(contact);
}
}
return users;
}
And then I used a Future Builder to return the result of the function as seen below:
return FutureBuilder(
future: userinfoGenerator(userConversations),
builder: (BuildContext context, AsyncSnapshot snapshot){
// Checking if future is resolved
if (snapshot.connectionState == ConnectionState.done) {
// If we got an error
if (snapshot.hasError) {
return Center(
child: CustomText(
label: '${snapshot.error} occurred',
),
);
// if we got our data
} else if (snapshot.hasData) {
// Extracting data from snapshot object
final data = snapshot.data;
return ListView.builder(
shrinkWrap: true,
itemCount: data.length,
itemBuilder: (BuildContext context, int index) {
List<String> theName = data[index].name
.split(" ");
return Padding(
padding: const EdgeInsets.only(
top: 12.0),
child: CustomListTile(
contact: data[index],
label: theName.length == 1
? theName[0][0]
: "${theName[0][0]} ${theName[theName
.length - 1][0]}"
),
);
}
);
}
}
return const Center(
child: CircularProgressIndicator(
color: kDefaultBackground,
),
);
},
);
I have been trying with last an hour but not getting solution and failing completely to understand why its showing an error...
I have created a function for fetching data,
I have placed print statement for seeing what does it returns...here it is printing data but while inside feature builder it showing an error...
when I run app its showing output with
list<dynamic> is not a subtype of type FutureOr<List<Map<String,dynamic>>
it means its executes snapshot.haserror part
here is my code
class _HomeScreenState extends State<HomeScreen> {
Future<List<Map<String,dynamic>>> fetchdata() async {
var resp =
await http.get(Uri.parse("https://jsonplaceholder.typicode.com/photos"));
print("fetchdata function showing"+json.decode(resp.body).toString());
return json.decode(resp.body);
}
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: MyBody(),
),
);
}
MyBody() {
return FutureBuilder<List<Map<String,dynamic>>>(
future: fetchdata(),
builder: (context, snapshot) {
print("Futurebuilder showing:"+snapshot.toString());
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
print('againt'+snapshot.toString());
List<Map<String,dynamic>> data = snapshot.data ?? [];
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.all(8.0),
child: Text(data[index]['title']));
});
}
}
},
);
}}
Future<List<Map<String, dynamic>>> fetchdata() async {
var resp = await http
.get(Uri.parse("https://jsonplaceholder.typicode.com/photos"));
print("fetchdata function showing" + json.decode(resp.body).toString());
List<dynamic> result = jsonDecode(resp.body);
return result.map((e) => e as Map<String, dynamic>).toList();
}
just change your function like this
Your API Call:
Future<List<dynamic>> getJobsData() async {
String url = 'https://jsonplaceholder.typicode.com/photos';
var response = await http.get(Uri.parse(url), headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
});
return json.decode(response.body);
}
Your Widget:
Center(
child: FutureBuilder<List<dynamic>>(
future: getJobsData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
var title = snapshot.data![index]['title'];
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: ListTile(
title: Text(title),
),
);
},
),
);
}
return CircularProgressIndicator();
},
),
),
Result->
I have created a demo project for showing orders using FutureBuilder but Its not showing order, instead its giving infinite loop , so where should I correct my code
Why it is infinite?
herewith I am sending code for my provider method to fetch orders and the code where I am using it
or is there any other better option to replace future builder..
Future<void> fetchandsetorders() async {
print('I am fetchandsetorders method of provider');
final url = Uri.parse(
mylink);
final response = await http.get(url);
final List<OrderItem> loadedorders = [];
final Map<String, dynamic> extradeddata = json.decode(response.body) as Map<String, dynamic>;
extradeddata.forEach((orderid, orderdata) {
loadedorders.add(
OrderItem(
id: orderid,
products: (orderdata['products'] as List<dynamic>).map((item) {
return CartItem(
id: item['id'],
title: item['title'],
quantity: item['qty'],
price: item['price']);
}).toList(),
amount: orderdata['amount'],
date: DateTime.parse(orderdata['date']),
),
);
});
_orders=loadedorders.reversed.toList();
notifyListeners();
}
class _OrderScreenState extends State<OrderScreen> {
#override
Widget build(BuildContext context) {
final orderdata = Provider.of<Orders>(context);
print('I am buildmethod');
return Scaffold(
appBar: AppBar(
backgroundColor: Color.fromRGBO(Random().nextInt(255),
Random().nextInt(255), Random().nextInt(255), 1),
title: Text('List of orders: ' + orderdata.ordercount.toString()),
),
drawer: AppDrawer(),
body: FutureBuilder(
future: Provider.of<Orders>(context, listen: false).fetchandsetorders(),
builder: (context,snapshop){
if(snapshop.connectionState==ConnectionState.waiting)
{
return Center(child: CircularProgressIndicator());
}
else
{
if(snapshop.error!=null)
{
return Text(snapshop.error.toString());
}
else
{
return ListView.builder(
itemCount: orderdata.ordercount,
itemBuilder: (context, index) {
return OrderItemWidget(
order: orderdata.orders[index],
);
});
}
}
},
),
);
}
}
create a state variable for Future like
late myFuture = Provider.of<Orders>(context, listen: false).fetchandsetorders(),
And use on
body: FutureBuilder(
future: myFuture,
I have a method that fetches a PatientLog from SQLite.However, This PatientLog table mapped to an object with a class named PatientLog. Inside this PatientLog class, several other objects such as Speciality, AttendingPhysician, Course, etc. I need to map these PatienLog records to a local object. However, I have to use nested Futures. I need to retrieve the data from this nested Future. Think of Future of Future.
This is my fetch method
Future<List<Future<PatientLog>>> getForms() async {
Database db = await instance.getDatabase;
List<Map<String, dynamic>> forms =
await db.query(_tablePatientLog, orderBy: 'id DESC');
Institute? institute;
AttendingPhysician? attendingPhysician;
Speciality? speciality;
Course? course;
List<Future<PatientLog>> list = forms.map((myMap) async {
int? courseId = myMap['course_id'] as int?;
int? specialityId = myMap['speciality_id'] as int?;
int? attendingId = myMap['attending_id'] as int?;
int? instituteId = myMap['institute_id'] as int?;
if (courseId != null) {
await getCourse(courseId).then((value) => course=value);
}
if (attendingId != null) {
await getAttending(attendingId).then((value) => attendingPhysician=value);
}
if (specialityId != null) {
await getSpeciality(specialityId).then((value) => speciality=value);
}
if (instituteId != null) {
await getInstitute(instituteId).then((value) => institute=value);
}
return PatientLog.fromMap(
myMap, institute, course, attendingPhysician, speciality);
}).toList();
return list;
}
I need to display that information on a screen. I get an error type 'List<Future<PatientLog>>' is not a subtype of type 'Future<Object?>?'
class _DraftsState extends State<Drafts> {
final SQFLiteHelper _helper = SQFLiteHelper.instance;
#override
void initState() {
super.initState();
_refresh();
}
late List<Future<PatientLog>> fromDatabase;
Future<dynamic> _refresh() async {
await _helper.getForms().then((value) async{
setState(() {
fromDatabase = value;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: _helper.getForms(),
builder: (BuildContext context,
AsyncSnapshot snapshot) {
if (snapshot.hasData && snapshot.data!.isEmpty) {
return Center(
child: Text(
"Henüz kaydedilmiş taslak bulunmamaktadır.",
textAlign: TextAlign.center,
style: TEXT_STYLE,
));
}
if (snapshot.hasError) {
return Center(
child: Text(
'Sanırım bir şeyler ters gitti.',
style: TEXT_STYLE,
));
}
if (snapshot.connectionState == ConnectionState.done) {
return RefreshIndicator(
backgroundColor: Colors.grey[700],
color: LIGHT_BUTTON_COLOR,
onRefresh: _refresh,
child: SizedBox(
height: MediaQuery.of(context).size.height,
child: ListView.builder(
shrinkWrap: true,
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics(),
),
itemCount: snapshot.data!.length,
itemBuilder: (BuildContext context, int index) {
return FutureBuilder(
future: snapshot.data,
builder: (context,innerSnap) {
return Text(innerSnap.toString());/*CustomListTile(
formData: innerSnap.data[index],
index: index,
routeTo: 1,
isDeletable: true,
);*/
}
);
},
),
),
);
}
return const Center(
child: Text("Nothing")//spinkit,
);
}),
);
}
}