So i tried to create a listview of a news with this API https://newsapi.org/s/us-news-api but when i tried to implement it in my App it keeps loading and never show the data.
here is my homepage code
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:medreminder/NewsArticle/components/list_tile.dart';
import 'package:medreminder/NewsArticle/models/article_models.dart';
import 'package:medreminder/NewsArticle/services/api_service.dart';
class NewsHomePage extends StatelessWidget {
//const NewsHomePage({super.key});
ApiService client = ApiService();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Get.isDarkMode?Colors.grey[600]:Colors.white,
leading: IconButton(
onPressed: ()=>Get.back(),
icon: Icon(Icons.arrow_back_ios,
color: Get.isDarkMode?Colors.white:Colors.grey
),
),
title: Text("News & Article", style: TextStyle(
color: Get.isDarkMode?Colors.white:Colors.black
),),
),
body: FutureBuilder(
future: client.getArticle(),
builder: (BuildContext context, AsyncSnapshot<List<Article>> snapshot) {
if(snapshot.hasData){
List<Article>? articles = snapshot.data;
return ListView.builder(
itemCount: articles!.length,
itemBuilder: (context, index) => listTile(articles[index])
);
}
return Center(child: CircularProgressIndicator(),);
},
),
);
}
}
my API Service
import 'dart:convert';
import 'package:http/http.dart';
import 'package:medreminder/NewsArticle/models/article_models.dart';
class ApiService {
final endPointUrl = "https://newsapi.org/v2/top-headlines?country=us&apiKey=cacee27fff544eb39d5fb29b28ca3788";
Future<List<Article>> getArticle() async{
Response res = await get(Uri.parse(endPointUrl));
if(res.statusCode==200){
Map<String, dynamic> json = jsonDecode(res.body);
List<dynamic> body = json['articles'];
List<Article> articles = body.map((dynamic item) => Article.fromJson(item)).toList();
return articles;
}else{
throw("Cant get the News");
}
}
}
here is my model class
import 'source_models.dart';
class Article{
Source source;
String author;
String title;
String description;
String url;
String urlToImage;
String publishedAt;
String content;
Article({
required this.source,
required this.author,
required this.title,
required this.description,
required this.url,
required this.urlToImage,
required this.publishedAt,
required this.content
});
factory Article.fromJson(Map<String, dynamic> json){
return Article(
source: Source.fromJson(json['source']),
author: json['author'] as String,
title: json['title'] as String,
description: json['description'] as String,
url: json['url'] as String,
urlToImage: json['urlToImage'] as String,
publishedAt: json['publishedAt'] as String,
content: json['content'] as String
);
}
}
Adding my customtile code
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:medreminder/NewsArticle/models/article_models.dart';
Widget listTile(Article article){
return Container(
margin: EdgeInsets.all(12),
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Get.isDarkMode?Colors.white:Colors.black,
borderRadius: BorderRadius.circular(18),
boxShadow: [
BoxShadow(
color: Get.isDarkMode?Colors.white:Colors.black,
blurRadius: 3
)
]
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(article.urlToImage)
),
borderRadius: BorderRadius.circular(8),
),
),
SizedBox(height: 9),
Container(
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(30),
),
child: Text(article.source.name),
),
SizedBox(height: 8,),
Text(article.title, style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),)
],
),
);
}
i dont know how this happening but i followed everysecond in a yt tutorial but still got this never stop loading. let me know if you guys needs to see my other codes if necessary. thankyou guys
I check your code, you have to update your Article class. Because some values are null in API response, so that causes issue. To handle that You have to generate dart model class for APIs response by using json to dart convertor.
Here is updated class:
class Articles {
List<Articles>? articles;
Articles({this.articles});
Articles.fromJson(Map<String, dynamic> json) {
if (json['articles'] != null) {
articles = <Articles>[];
json['articles'].forEach((v) {
articles!.add(Articles.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
if (articles != null) {
data['articles'] = articles!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Article {
Source? source;
String? author;
String? title;
String? description;
String? url;
String? urlToImage;
String? publishedAt;
String? content;
Article(
{source,
author,
title,
description,
url,
urlToImage,
publishedAt,
content});
Article.fromJson(Map<String, dynamic> json) {
source = json['source'] != null ? Source.fromJson(json['source']) : null;
author = json['author'];
title = json['title'];
description = json['description'];
url = json['url'];
urlToImage = json['urlToImage'];
publishedAt = json['publishedAt'];
content = json['content'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
if (source != null) {
data['source'] = source!.toJson();
}
data['author'] = author;
data['title'] = title;
data['description'] = description;
data['url'] = url;
data['urlToImage'] = urlToImage;
data['publishedAt'] = publishedAt;
data['content'] = content;
return data;
}
}
class Source {
String? id;
String? name;
Source({id, name});
Source.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['name'] = name;
return data;
}
}
and listTile widget will be :
Widget listTile(Article article) {
return Container(
margin: EdgeInsets.all(12),
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(18),
boxShadow: [BoxShadow(color: Colors.black, blurRadius: 3)]),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
image: DecorationImage(image: NetworkImage(article.urlToImage!)),
borderRadius: BorderRadius.circular(8),
),
),
SizedBox(height: 9),
Container(
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(30),
),
child: Text(article.source!.name!),
),
SizedBox(
height: 8,
),
Text(
article.title!,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
)
],
),
);
}
I run this API in postman and get response in html format. There in response they mentioned to get reponse by this API
https://newsapi.org/v2/top-headlines?country=gb&apiKey=API_KEY
Try this one, Maybe it works.
Related
I am trying to get a JSON response from this server. I am new to flutter and I'm confused about how to get it done.
can anybody point out what I did wrong???
class RESTAPIService{
String apiUrl = "https://mocki.io/v1/048e68cc-9ddb-4aca-8264-6e9f8f273fd2";
Future<List<User>> getUsers() async{
final response = await http.get(Uri.parse(apiUrl));
print(response.body);
if(response.statusCode == 200){
throw getUsersList(response.body);
}else{
throw Exception("Couldn't fetch data");
}
}
List<User> getUsersList(String responseBody){
final parsebody = json.decode(responseBody).cast<Map<String, dynamic>>();
return parsebody.map<User>({(json) => User(name: "", city: "", image: "").fromJson(json)}).toList();
}
}
I did my conversions like bellow.
class User{
String name;
String city;
String image;
User({required this.name, required this.city, required this.image});
Map<String, dynamic> fromJson(Map<String, dynamic> json){
name = json['name'];
city = json['city'];
image = json['image'];
return json;
}
Map<String, dynamic> toJson(){
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['city'] = this.city;
data['image'] = this.image;
return data;
}
}
I called the json data here. When the app runs it only shows "Loading..." and won't show the json response. But I do get the json response from the server. it just doesn't show in my app UI.
child: FutureBuilder(
future: apiService.getUsers(),
builder: (context, snapShot){
if(snapShot.hasData){
return ListView.builder(
itemCount: snapShot.data!.length,
itemBuilder: (context, index){
return InkWell(
onTap: (){
},
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
blurRadius: 3, spreadRadius: 3,
color: Colors.grey.withOpacity(0.3),
)
]
),
margin: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
child: ListTile(
title: Text(snapShot.data![index].name ?? '', style: TextStyle(
fontSize: 18, color: Colors.black,
),),
subtitle: Text(snapShot.data![index].city ?? '', style: TextStyle(
fontSize: 15, color: Colors.black,
),),
leading: ClipOval(
child: Image.network(snapShot.data![index].image, fit: BoxFit.cover, width: 60, height: 60,),
),
),
),
);
}
);
}else{
return Container(
child: Center(
child: Text("Loading...", style: TextStyle(
color: Colors.black, fontSize: 15,
)),
),
);
}
},
),`
Your response is list,
So it should be
List<User> getUsersList(String responseBody) {
final parsebody = json.decode(responseBody) as List?;
return (parsebody?.map((e) => User.fromMap(e)))?.toList() ?? [];
}
Try using factory model like
class User {
String name;
String city;
String image;
User({required this.name, required this.city, required this.image});
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
result.addAll({'name': name});
result.addAll({'city': city});
result.addAll({'image': image});
return result;
}
factory User.fromMap(Map<String, dynamic> map) {
return User(
name: map['name'] ?? '',
city: map['city'] ?? '',
image: map['image'] ?? '',
);
}
String toJson() => json.encode(toMap());
factory User.fromJson(String source) => User.fromMap(json.decode(source));
}
i was trying to create a news app with news api, but i got a weird error when 1 tile of the news actually showedup but there's also an error message in the app.
i need help with how do i get rid of this error.
so below here is the codes for my app
here is my homepage code
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:medreminder/NewsArticle/components/list_tile.dart';
import 'package:medreminder/NewsArticle/models/article_models.dart';
import 'package:medreminder/NewsArticle/services/api_service.dart';
class NewsHomePage extends StatelessWidget {
//const NewsHomePage({super.key});
ApiService client = ApiService();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Get.isDarkMode?Colors.grey[600]:Colors.white,
leading: IconButton(
onPressed: ()=>Get.back(),
icon: Icon(Icons.arrow_back_ios,
color: Get.isDarkMode?Colors.white:Colors.grey
),
),
title: Text("News & Article", style: TextStyle(
color: Get.isDarkMode?Colors.white:Colors.black
),),
),
body: FutureBuilder(
future: client.getArticle(),
builder: (BuildContext context, AsyncSnapshot<List<Article>> snapshot) {
if(snapshot.hasData){
List<Article>? articles = snapshot.data;
return ListView.builder(
itemCount: articles!.length,
itemBuilder: (context, index) => listTile(articles[index])
);
}
return Center(child: CircularProgressIndicator(),);
},
),
);
}
}
My APIService class
import 'dart:convert';
import 'package:http/http.dart';
import 'package:medreminder/NewsArticle/models/article_models.dart';
class ApiService {
final endPointUrl = "https://newsapi.org/v2/top-headlines?country=gb&apiKey=cacee27fff544eb39d5fb29b28ca3788";
Future<List<Article>> getArticle() async{
Response res = await get(Uri.parse(endPointUrl));
if(res.statusCode==200){
Map<String, dynamic> json = jsonDecode(res.body);
List<dynamic> body = json['articles'];
List<Article> articles = body.map((dynamic item) => Article.fromJson(item)).toList();
return articles;
}else{
throw("Cant get the News");
}
}
}
my News/Article model class
import 'source_models.dart';
import 'package:medreminder/NewsArticle/components/list_tile.dart';
import 'package:medreminder/NewsArticle/models/source_models.dart';
class Articles {
List<Articles>? articles;
Articles({this.articles});
Articles.fromJson(Map<String, dynamic> json) {
if (json['articles'] != null) {
articles = <Articles>[];
json['articles'].forEach((v) {
articles!.add(Articles.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
if (articles != null) {
data['articles'] = articles!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Article {
Source? source;
String? author;
String? title;
String? description;
String? url;
String? urlToImage;
String? publishedAt;
String? content;
Article(
{source,
author,
title,
description,
url,
urlToImage,
publishedAt,
content});
Article.fromJson(Map<String, dynamic> json) {
source = json['source'] != null ? Source.fromJson(json['source']) : null;
author = json['author'];
title = json['title'];
description = json['description'];
url = json['url'];
urlToImage = json['urlToImage'];
publishedAt = json['publishedAt'];
content = json['content'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
if (source != null) {
data['source'] = source!.toJson();
}
data['author'] = author;
data['title'] = title;
data['description'] = description;
data['url'] = url;
data['urlToImage'] = urlToImage;
data['publishedAt'] = publishedAt;
data['content'] = content;
return data;
}
}
class Source {
String? id;
String? name;
Source({id, name});
Source.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['name'] = name;
return data;
}
}
and lastly my custometile class
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:medreminder/NewsArticle/models/article_models.dart';
Widget listTile(Article article) {
return Container(
margin: EdgeInsets.all(12),
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(18),
boxShadow: [BoxShadow(color: Colors.black, blurRadius: 3)]),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
image: DecorationImage(image: NetworkImage(article.urlToImage!)),
borderRadius: BorderRadius.circular(8),
),
),
SizedBox(height: 9),
Container(
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(30),
),
child: Text(article.source!.name!),
),
SizedBox(
height: 8,
),
Text(
article.title!,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
)
],
),
);
}
let me know if you guys needs to see the other codes if neccesary. thankyou so much guys
add FutureBuilder return Type and check it!
body: FutureBuilder<List<Article>>(
future: client.getArticle(),
builder: (BuildContext context, AsyncSnapshot<List<Article>> snapshot) {
if(snapshot.hasData&&snapshot.data!=null&& snapshot.data!.isNotEmpty){
List<Article>? articles = snapshot.data;
return ListView.builder(
itemCount: articles!.length,
itemBuilder: (context, index) => listTile(articles[index])
);
}
return Center(child: CircularProgressIndicator(),);
},
),
);
it is because you have used ! null check operator which is causing error when the value is null try replacing this operator by this ? operator like this.
change this line
itemCount: articles!.length,
to this
itemCount: articles?.length,
In API response some of response data has null value : article.urlImage is null, which cause this issue. To handle it either you have to provide different container style or default image.
Code as below: In listTile for different container style
article.urlToImage != null
? Container(
decoration: BoxDecoration(
image:
DecorationImage(image: NetworkImage(article.urlToImage!)),
borderRadius: BorderRadius.circular(8),
),
)
: Container(),
OR In listTile for default image :
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(article.urlToImage != null
? article.urlToImage!
: "Your defualt image here")),
borderRadius: BorderRadius.circular(8),
),
)
i am working on a project and my problem is related to Nested Object in api. I want to get message from my data object and it is not accessible and my model class don't give no thing about message. Actually I want from this line
"data":"{"message":"Saim12345 Has a Confirmed Appointment with you Dated 15-06-2022 at 06:20 PM at Online Video Consultation"}", .
Only the message value such as "Saim12345 Has a Confirmed Appointment with you Dated 15-06-2022 at 06:20 PM at Online Video Consultation"
I have tried JsonEcode to get its Index but not working well and i am also Created Seperate class of Data and created String message but that accesseed but gives null error if anybody can help me please response me as soon as possible
For Further This is
my Model Class
List<NotificationModel> notificationModelFromJson(String str) => List<NotificationModel>.from(json.decode(str).map((x) => NotificationModel.fromJson(x)));
String notificationModelToJson(List<NotificationModel> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class NotificationModel {
NotificationModel({
this.id,
this.type,
this.notifiableType,
this.notifiableId,
this.data,
this.readAt,
this.createdAt,
this.updatedAt,
});
double id;
String type;
String notifiableType;
int notifiableId;
String data;
DateTime readAt;
DateTime createdAt;
DateTime updatedAt;
factory NotificationModel.fromJson(Map<String, dynamic> json) => NotificationModel(
id: json["id"].toDouble(),
type: json["type"],
notifiableType: json["notifiable_type"],
notifiableId: json["notifiable_id"],
data: json["data"],
readAt: DateTime.parse(json["read_at"]),
createdAt: DateTime.parse(json["created_at"]),
updatedAt: DateTime.parse(json["updated_at"]),
);
Map<String, dynamic> toJson() => {
"id": id,
"type": type,
"notifiable_type": notifiableType,
"notifiable_id": notifiableId,
"data": data,
"read_at": readAt.toIso8601String(),
"created_at": createdAt.toString(),
"updated_at": updatedAt.toString(),
};
}
This my Class
class PatientNotification extends StatefulWidget {
final int notificationModelId;
const PatientNotification({Key key, this.notificationModelId}) : super(key: key);
#override
State<PatientNotification> createState() => _PatientNotificationState();
}
class _PatientNotificationState extends State<PatientNotification> {
NotificationModel notification;
List<NotificationModel> notificationModelList = [];
bool loading = true;
Map mapResponse;
void getNotifications() async {
notificationModelList = [];
Network network = new Network();
var response = await network.getData("/notifications");
log(response.body);
if (response.statusCode == 200) {
var json = cnv.jsonDecode(response.body);
// try{
if (json != null) {
json.forEach((element) {
notificationModelList.add(new NotificationModel.fromJson(element));
});
print(notificationModelList.length);
}
// }catch(e){
// // log(e);
// }
}
setState(() {
notificationModelList = notificationModelList;
// datalist=datalist;
loading = false;
});
}
#override
void initState() {
getNotifications();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(
Icons.arrow_back_rounded,
color: AppColor.primary,
//size: .0,
// semanticLabel: 'Text to announce in accessibility modes',
),
),
TextButton(
onPressed: getNotifications,
child: Text(
"Notifications",
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 24,
letterSpacing: 0.7,
color: Colors.black),
),
),
],
),
SizedBox(
height: 10,
),
Expanded(child: SingleChildScrollView(
child: Container(
height: MediaQuery
.of(context)
.size
.height * 0.8,
child: loading ? AppWidgetsCard.getProgressIndicator()
: notificationModelList.isEmpty
? AppWidgetsCard.getEmptyCard('Notification') :
ListView.builder(
itemCount: notificationModelList.length,
itemBuilder: (context, index) {
NotificationModel data = notificationModelList[index];
String dateFormate = DateFormat()
.add_yMMMEd()
.format(DateTime.parse(
data.createdAt.toString()));
String time = DateFormat()
.add_jm()
.format(DateTime.parse(
data.createdAt.toString()));
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
),
height: 110,
width: MediaQuery
.of(context)
.size
.width,
padding: EdgeInsets.symmetric(
horizontal: 1, vertical: 5),
child: Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(15.0),
),
child: Row(
children: [
Container(
height: 100,
width: 100,
decoration: BoxDecoration(
borderRadius:
BorderRadius.only(
bottomLeft:
Radius.circular(15),
topLeft:
Radius.circular(15),
// topRight:
// Radius.circular(15),
// bottomRight:
// Radius.circular(15),
),
image: DecorationImage(
image: NetworkImage(
'https://emedz.net/images/doctors/male-avi.jpg'),
fit: BoxFit.fill
)
),
),
Expanded(
child: Padding(
padding:
const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Expanded(
child: Column(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Text(
data.data,
style: TextStyle(
fontSize: 12,
color: Colors
.black,
fontWeight:
FontWeight
.bold),
),
Expanded(
child:
SizedBox()),
Text('',
style: TextStyle(
fontSize: 10,
color: Colors
.blue),
),
Text(
'$dateFormate at $time ',
maxLines: 2,
style: TextStyle(
fontSize: 14,
),
),
],
),
),
],
),
),
),
],
),
),
);
}))
),
)
],
),
));
}
}
Unfortunately your data is String you have to convert it to json and parse it
so do this
dataJson = data.substring(1, data.length-1); //it will remove double quotes from string
then send this json to Data Model using......
final dataModel = dataModelFromJson(dataJson);// this line where you pass dataJson
Below is your Data Model Class.......
DataModel dataModelFromJson(String str) =>
DataModel.fromJson(json.decode(str));
String dataModelToJson(DataModel data) => json.encode(data.toJson());
class DataModel {
DataModel({
#required this.message,
});
String message;
factory DataModel.fromJson(Map<String, dynamic> json) => DataModel(
message: json["message"],
);
Map<String, dynamic> toJson() => {
"message": message,
};
}
I have resolved it in way such as
and printed my message
This is the result that i want Saim12345 Has a Confirmed Appointment with you Dated 15-06-2022 at 06:20 PM at Online Video Consultation
if (json != null) {
json.forEach((element) {
Map obj= element;
message=obj['data'];
message = message.replaceRange(0, 12, '');
message = message.replaceRange((message.length-2), message.length, '');
print(message);
// var klk= cnv.jsonDecode(plm);
print(message.toString());
notificationModelList.add(new NotificationModel.fromJson(element));
});
print(notificationModelList.length);
}
Having an error in execution and returning a null value when the app is debugging
Getting The Bellow Error Debug Code
lib/quran/surat_list_detail.dart:16:27: Error: Field '_ayatList'
should be initialized because its type 'Future<List>'
doesn't allow null.
'Future' is from 'dart:async'.
'List' is from 'dart:core'.
'SuratAyat' is from 'package:issaq_pro/model/surat_ayat_model.dart' ('lib/model/surat_ayat_model.dart'). Future<List>
_ayatList;
import 'package:flutter/material.dart';
import 'package:issaq_pro/model/surat_ayat_model.dart';
class SuratListDetail extends StatefulWidget {
final String suratId;
final String suratName;
final String totalAyat;
SuratListDetail(this.suratId, this.suratName, this.totalAyat);
#override
_SuratListDetailState createState() => _SuratListDetailState();
}
class _SuratListDetailState extends State<SuratListDetail> {
Future<List<SuratAyat>> _ayatList;
#override
void initState() {
super.initState();
_ayatList = getSuratAyatData(widget.suratId);
}
ListView _suratListView(data) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (BuildContext context, index) {
return Card(
elevation: 8,
child: _tile(
data[index].ayatNumber,
data[index].ayatText,
),
);
},
);
}
ListTile _tile(
String ayatNumber,
String ayatText,
) =>
ListTile(
contentPadding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
leading: Container(
padding: EdgeInsets.only(right: 12),
decoration: BoxDecoration(
border: Border(
right: BorderSide(width: 1, color: Colors.black),
),
),
child: CircleAvatar(
backgroundColor: Colors.amberAccent,
child: Text(
'$ayatNumber',
style: TextStyle(
color: Colors.black,
fontSize: 12,
),
),
),
),
title: Text(
ayatText,
style: TextStyle(fontSize: 24),
),
trailing: Icon(
Icons.keyboard_arrow_right,
color: Colors.white,
size: 30,
),
);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.suratName,
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.black,
),
body: SafeArea(
child: Center(
child: FutureBuilder<List<SuratAyat>>(
future: _ayatList,
builder: (BuildContext context,AsyncSnapshot snapshot) {
if (snapshot.hasData) {
List<SuratAyat> data = snapshot.data;
return _suratListView(data);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
),
),
);
}
}
MODELS :
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
class QuranSurat {
final String id;
final String suratName;
final String suratText;
final String translate;
final String totalAyat;
QuranSurat(
{required this.id,
required this.suratName,
required this.suratText,
required this.translate,
required this.totalAyat});
factory QuranSurat.createSuratList(Map<String, dynamic> json) {
return QuranSurat(
id: json['id'].toString(),
suratName: json['surat_name'],
suratText: json['surat_text'],
translate: json['surat_terjemahan'],
totalAyat: json['count_ayat'].toString());
}
}
Future<List<QuranSurat>> getSuratList() async {
try {
final apiUrl = 'https://quran.kemenag.go.id/index.php/api/v1/surat';
final response = await http.get(Uri.parse(apiUrl));
List result = json.decode(response.body)['data'];
return result
.map((surat) => new QuranSurat.createSuratList(surat))
.toList();
} catch (err) {
throw err;
}
}
just add late before Future it should work
late Future<List<SuratAyat>> _ayatList;
I am trying to fetch the data from API using StreamBuilder, Kindly help with this error
Future<dynamic>' is not a subtype of type 'Stream<List<dynamic>>.
Basically we are fetching data and displaying data with help of ListView.buider and StreamBuilder:
Search_product.dart
import 'dart:async';
import 'package:beauty/user.dart';
import 'package:flutter/material.dart';
import 'package:beauty/backend.dart';
class SearchProduct extends StatefulWidget {
#override
_SearchProductState createState() => _SearchProductState();
}
class _SearchProductState extends State<SearchProduct> {
List<Welcome> _welcome;
Backend backend = new Backend();
bool waiting = true;
Stream _stream;
#override
void initState() {
// TODO: implement initState
super.initState();
Backend.getData().then((welcome) {
setState(() {
_welcome = welcome;
waiting = false;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFEBEAEF),
appBar: AppBar(
title: Row(children: [
SizedBox(
width: 70.0,
),
Text(
'Search Product',
style: TextStyle(
color: Colors.black,
),
),
SizedBox(
width: 70.0,
),
Flexible(
child: CircleAvatar(
child: Image.asset('assets/her.png'),
),
),
]),
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.black,
),
onPressed: () {},
),
backgroundColor: Color(0xFFEBEAEF),
),
body: Column(children: [
Container(
color: Colors.white70,
child: TextField(
decoration: InputDecoration(
prefixIcon: Icon(
Icons.search,
color: Colors.grey,
),
hintText: 'Search for product',
contentPadding:
EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0)),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white70, width: 1.0),
borderRadius: BorderRadius.all(Radius.circular(12.0)),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white70, width: 2.0),
borderRadius: BorderRadius.all(Radius.circular(12.0)),
),
),
style: TextStyle(color: Colors.black),
),
),
Container(
child: waiting
? SizedBox(
width: 50,
height: 50,
child: CircularProgressIndicator(),
)
: Expanded(
child: StreamBuilder(
stream: Backend.getData(),
builder: (BuildContext context,
AsyncSnapshot<List<dynamic>> snapshot) {
return ListView.builder(
padding: EdgeInsets.all(8),
itemCount: null == _welcome ? 0 : _welcome.length,
itemBuilder: (BuildContext context, int index) {
Welcome welcome = _welcome[index];
return Card(
child: Column(
children: <Widget>[
ListTile(
leading: CircleAvatar(
radius: 30,
backgroundImage: NetworkImage(snapshot
.data[index].welcome.image),
),
title: Text(
snapshot.data[index].welcome.title),
subtitle: Text(snapshot
.data[index].welcome.description),
trailing: Text(snapshot
.data[index].welcome.price
.toString()),
)
],
),
);
});
}),
),
),
]));
}
}
Backend.dart
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:beauty/user.dart';
class Backend {
static getData() async {
try {
var url = Uri.parse('https://fakestoreapi.com/products');
var response = await http.get(url);
if (response.statusCode == 200) {
return welcomeFromJson(response.body);
} else {
List error_message = ['error'];
return error_message;
}
} catch (e) {
print(e);
}
}
}
user.dart
import 'dart:convert';
List<Welcome> welcomeFromJson(String str) =>
List<Welcome>.from(json.decode(str).map((x) => Welcome.fromJson(x)));
String welcomeToJson(List<Welcome> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Welcome {
Welcome({
this.id,
this.title,
this.price,
this.description,
this.category,
this.image,
this.rating,
});
int id;
String title;
double price;
String description;
Category category;
String image;
Rating rating;
factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
id: json["id"],
title: json["title"],
price: json["price"].toDouble(),
description: json["description"],
category: categoryValues.map[json["category"]],
image: json["image"],
rating: Rating.fromJson(json["rating"]),
);
Map<String, dynamic> toJson() => {
"id": id,
"title": title,
"price": price,
"description": description,
"category": categoryValues.reverse[category],
"image": image,
"rating": rating.toJson(),
};
}
enum Category { MEN_S_CLOTHING, JEWELERY, ELECTRONICS, WOMEN_S_CLOTHING }
final categoryValues = EnumValues({
"electronics": Category.ELECTRONICS,
"jewelery": Category.JEWELERY,
"men's clothing": Category.MEN_S_CLOTHING,
"women's clothing": Category.WOMEN_S_CLOTHING
});
class Rating {
Rating({
this.rate,
this.count,
});
double rate;
dynamic count;
factory Rating.fromJson(Map<String, dynamic> json) => Rating(
rate: json["rate"].toDouble(),
count: json["count"],
);
Map<String, dynamic> toJson() => {
"rate": rate,
"count": count,
};
}
class EnumValues<T> {
Map<String, T> map;
Map<T, String> reverseMap;
EnumValues(this.map);
Map<T, String> get reverse {
if (reverseMap == null) {
reverseMap = map.map((k, v) => new MapEntry(v, k));
}
return reverseMap;
}
}
The response type from Backend.getData is a Future, not a Stream.
Replace
StreamBuilder(
stream: Backend.getData(),
builder: (BuildContext context, AsyncSnapshot<List<dynamic>> snapshot) {
with
FutureBuilder(
future: Backend.getData(),
builder: (BuildContext context, AsyncSnapshot<List<dynamic>> snapshot) {
//show visual loading
if(!snapshot.hasData) return Center(child: CircularProgressIndicator());
The error occurred because of type mismatch.
Current
Expected
Expected data
List<dynamic>
List<Welcome>?
stream
Future<dynamic>
Stream<List<Welcome>?>
snapshot
AsyncSnapshot<List<dynamic>>
AsyncSnapshot<List<Welcome>?>
StreamBuilder expects a stream instead of Future<T>.
If you expect new data coming from Future, you may consider using FutureBuilder instead.
So, here's how we fix it.
Create a StreamController
Pass the stream currently controlled by StreamController to StreamBuilder so it can listen for new data event
Call getData(), wait until it completes and returns expected data List<Welcome>? (can be a list of Welcome if successful or null if failed)
Next, send the data as data event to the stream
We also have to check the event data and connectionState, then handle them accordingly, e.g. display CircularProgressIndicator() while waiting for data, or certain widget when data exists.
The revised code follows the above steps so it should be easy to understand.
search_product.dart
import 'package:flutter/material.dart';
import 'user.dart';
import 'backend.dart';
class SearchProduct extends StatefulWidget {
#override
_SearchProductState createState() => _SearchProductState();
}
class _SearchProductState extends State<SearchProduct> {
Backend backend = Backend();
#override
void initState() {
super.initState();
backend.addDataToStream();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFEBEAEF),
appBar: AppBar(
title: Row(children: [
SizedBox(
width: 70.0,
),
Text(
'Search Product',
style: TextStyle(
color: Colors.black,
),
),
SizedBox(
width: 70.0,
),
Flexible(
child: CircleAvatar(
//child: Image.asset('assets/her.png'),
),
),
]),
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.black,
),
onPressed: () {},
),
backgroundColor: Color(0xFFEBEAEF),
),
body: Column(
children: [
Container(
color: Colors.white70,
child: TextField(
decoration: InputDecoration(
prefixIcon: Icon(
Icons.search,
color: Colors.grey,
),
hintText: 'Search for product',
contentPadding:
EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0)),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white70, width: 1.0),
borderRadius: BorderRadius.all(Radius.circular(12.0)),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white70, width: 2.0),
borderRadius: BorderRadius.all(Radius.circular(12.0)),
),
),
style: TextStyle(color: Colors.black),
),
),
Expanded(
child: StreamBuilder<List<Welcome>?>(
initialData: null,
stream: backend.welcomeStream,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
case ConnectionState.none:
return Center(
child: CircularProgressIndicator(),
);
case ConnectionState.active:
case ConnectionState.done:
if (snapshot.hasError) {
return Text('Error happened!');
}
var data = snapshot.data;
if (data == null) {
return Text('No data!');
}
return ListView.builder(
padding: EdgeInsets.all(8),
itemCount: data.length,
itemBuilder: (BuildContext context, int index) {
Welcome? welcome = data[index];
return Card(
child: Column(
children: <Widget>[
ListTile(
leading: CircleAvatar(
radius: 30,
backgroundImage: welcome.image == null
? null
: NetworkImage(welcome.image!),
),
title: Text(welcome.title ?? ''),
subtitle: Text(welcome.description ?? ''),
trailing: Text(welcome.price.toString()),
)
],
),
);
},
);
}
},
),
),
],
),
);
}
}
backend.dart
import 'dart:async';
import 'package:http/http.dart' as http;
import 'user.dart';
class Backend {
StreamController<List<Welcome>?> _welcomeController = StreamController();
Stream<List<Welcome>?> get welcomeStream => _welcomeController.stream;
Future<void> addDataToStream() async {
await getData()
.then((List<Welcome>? value) => _welcomeController.add(value));
}
static Future<List<Welcome>?> getData() async {
try {
var url = Uri.parse('https://fakestoreapi.com/products');
var response = await http.get(url);
if (response.statusCode == 200) {
return welcomeFromJson(response.body);
} else {
print(response.statusCode);
return null;
}
} catch (e) {
print(e);
}
}
}
user.dart
import 'dart:convert';
List<Welcome> welcomeFromJson(String str) =>
List<Welcome>.from(json.decode(str).map((x) => Welcome.fromJson(x)));
String welcomeToJson(List<Welcome> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Welcome {
Welcome({
this.id,
this.title,
this.price,
this.description,
this.category,
this.image,
this.rating,
});
int? id;
String? title;
double? price;
String? description;
Category? category;
String? image;
Rating? rating;
factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
id: json["id"],
title: json["title"],
price: json["price"].toDouble(),
description: json["description"],
category: categoryValues.map[json["category"]],
image: json["image"],
rating: Rating.fromJson(json["rating"]),
);
Map<String, dynamic> toJson() => {
"id": id,
"title": title,
"price": price,
"description": description,
"category": categoryValues.reverse?[category],
"image": image,
"rating": rating?.toJson(),
};
}
enum Category { MEN_S_CLOTHING, JEWELERY, ELECTRONICS, WOMEN_S_CLOTHING }
final categoryValues = EnumValues({
"electronics": Category.ELECTRONICS,
"jewelery": Category.JEWELERY,
"men's clothing": Category.MEN_S_CLOTHING,
"women's clothing": Category.WOMEN_S_CLOTHING
});
class Rating {
Rating({
this.rate,
this.count,
});
double? rate;
dynamic count;
factory Rating.fromJson(Map<String, dynamic> json) => Rating(
rate: json["rate"].toDouble(),
count: json["count"],
);
Map<String, dynamic> toJson() => {
"rate": rate,
"count": count,
};
}
class EnumValues<T> {
Map<String, T> map;
Map<T, String>? reverseMap;
EnumValues(this.map);
Map<T, String>? get reverse {
if (reverseMap == null) {
reverseMap = map.map((k, v) => new MapEntry(v, k));
}
return reverseMap;
}
}