trying to display my variable value but output is null - android

I'm doing a project in Flutter in which I'm getting live bit rate using a API and I'm getting my rate but can't display on my screen its say it null..! code below:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'coin_data.dart';
import 'dart:io' show Platform;
import 'networking.dart';
class PriceScreen extends StatefulWidget {
#override
_PriceScreenState createState() => _PriceScreenState();
}
class _PriceScreenState extends State<PriceScreen> {
BitNetwork bitNetwork = BitNetwork('$BitCoinURL/BTC/USD?apikey=$BitCoinKey');
int bitRate;
void getCurrentBitRate() async {
dynamic bitData = await bitNetwork.getData();
double temp = bitData['rate'];
bitRate = temp.toInt();
print(bitRate);
}
String selectedCurrency = 'USD';`enter code here`
#override
Widget build(BuildContext context) {
getCurrentBitRate();
return Scaffold(
appBar: AppBar(
title: Text('Coin Ticker'),
),`enter code here`
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(18.0, 18.0, 18.0, 0),
child: Card(
color: Colors.lightBlueAccent,
elevation: 5.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 15.0, horizontal: 28.0),
child: Text(
'1 BTC = $bitRate USD',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
),
),
),
),
),
Container(
height: 150.0,
alignment: Alignment.center,
padding: EdgeInsets.only(bottom: 30.0),
color: Colors.lightBlue,
child: Platform.isIOS ? iOSPicker() : androidDropdown()),
],
),
);
}
}
answer in console:
I/flutter (14181): 47131
I/flutter (14181): 47131
I/flutter (14181): 47129
output on screen is = 1 BTC = null USD. => ????

You need to wait for currency loading, wrap your widget to FutureBuilder:
Future<int> getCurrentBitRate() async {
dynamic bitData = await bitNetwork.getData();
double temp = bitData['rate'];
return temp.toInt();
}
// build method
child: FutureBuilder<int>(
future: getCurrentBitRate(),
builder (context, snapshot) {
if (snapshot.hasData) {
final bitRate = snapshot.data;
return Column(
// Your column here.
);
}
return CircularProgressIndicator();
}
),
Also, you can find more information about how to work with async features here and read more about FutureBuilder here.

The problem is you're not awaiting getCurrentBitRate() and you are also calling it in your build method. Only UI code should be in the build method. What I recommend you do is override initState() and call it in there (Still can't await it, but it will be called before build);
#override
initState(){
getCurrentBitRate();
super.initState();
}
This will help with your issue, but it's not the best solution. I recommend looking up tutorials on some external state management system, such as BLoC, Provider and/or RxDart. This will make situations like this much easier to debug.

The bitRate value is null because you are calling it in build function & your method getCurrentBitRate() is an async method, which means that the method will wait to get the value but till then your build method would already finish rendering the widgets with bitRate value still null.
There are multiple ways to fix this but the one I would recommend is as follows:
Call your method getCurrentBitRate() in initState method & remove it from the build function as it is the first method that runs in your widget & use setState so that updated value of bitRate is shown in your widget.
class _PriceScreenState extends State<PriceScreen> {
BitNetwork bitNetwork = BitNetwork('$BitCoinURL/BTC/USD?apikey=$BitCoinKey');
int bitRate;
#override
void initState() {
super.initState();
getCurrentBitRate(); // Call it in initState & use setState
}
void getCurrentBitRate() async {
dynamic bitData = await bitNetwork.getData();
double temp = bitData['rate'];
bitRate = temp.toInt();
print(bitRate);
if (mounted) { // <--- mounted property checks whether your widget is still present in the widget tree
setState((){}); // Will update the UI once the value is retrieved
}
}
String selectedCurrency = 'USD';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Coin Ticker'),
),`enter code here`
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(18.0, 18.0, 18.0, 0),
child: Card(
color: Colors.lightBlueAccent,
elevation: 5.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 15.0, horizontal: 28.0),
child: Text(
'1 BTC = $bitRate USD',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
),
),
),
),
),
Container(
height: 150.0,
alignment: Alignment.center,
padding: EdgeInsets.only(bottom: 30.0),
color: Colors.lightBlue,
child: Platform.isIOS ? iOSPicker() : androidDropdown()),
],
),
);
}
}

It's null because when build() is called, getCurrentBitRate() didn't complete it's job yet.
For those operations FutureBuilder is one of the best widget. It just needs a future, and a builder to declare what to do after the data received.
// CHANGE TO FUTURE STYLE
Future<Int> getCurrentBitRate() async {
dynamic bitData = await bitNetwork.getData();
double temp = bitData['rate'];
bitRate = temp.toInt();
print(bitRate);
return bitRate;
}
Then change build structure to this
// DECLARE A FUTURE FOR getCurrentBitRate()
Future _future;
initState(){
_future = await getCurrentBitRate();
super.initState();
}
#override
Widget build(BuildContext context) {
// getCurrentBitRate(); REMOVE THIS LINE
return FutureBuilder(
future: _future,
builder: (context, snapshot) {
if(snapshot.hasData){
// YOUR DATA IS READY
double temp = snapshot.data['rate'];
// JUST CONTINUE REST OF ORIGINAL CODE BELOW
return Scaffold(
appBar: AppBar(
title: Text('Coin Ticker'),
),
...
}
}
);

Related

Not able to show the items list in drawer widget

I have been building this quiz app using flutter and I seem to have encountered an issue. The problem is that I have made a drawer in the App where I display all the topics and their respective quizzes, and for the user currently logged in, the leading widget inside the ListTile widget can take 2 icon values depending on whether the user has completed the quiz or not. For some reason, the Icon doesn't seem to update for the quizzes that are actually complete.
I have basically tried creating a list of all the quizzes that the user has completed and checking whether the list contains the quiz represented by each ListTile. For some reason, I can't seem to make it work.
here is the code for my 'drawer.dart' file :
class AppTopicDrawer extends StatelessWidget {
final List<Topic> topics;
const AppTopicDrawer({super.key, required this.topics});
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView.separated(
shrinkWrap: true,
itemBuilder: ((context, index) {
var topic = topics[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 30, 10, 30),
child: Text(
topic.title,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
),
QuizList(topic: topic),
],
);
}),
separatorBuilder: ((context, index) {
return const Divider();
}),
itemCount: topics.length,
),
);
}
}
class QuizList extends StatelessWidget {
final Topic topic;
const QuizList({super.key, required this.topic});
#override
Widget build(BuildContext context) {
return Column(
children: topic.quizzes.map((e) {
return Card(
elevation: 4,
margin: const EdgeInsets.all(10.0),
child: InkWell(
onTap: (() {}),
child: Container(
padding: const EdgeInsets.fromLTRB(5, 10, 5, 10),
child: ListTile(
title: Text(e.title),
subtitle: Text(
e.description,
style: const TextStyle(fontSize: 12),
),
leading: QuizBadge(topic: topic, quizId: e.id),
)),
),
);
}).toList(),
);
}
}
class QuizBadge extends StatelessWidget {
const QuizBadge({super.key, required this.topic, required this.quizId});
final Topic topic;
final String quizId;
#override
Widget build(BuildContext context) {
Report report = Provider.of<Report>(context);
List completed = report.topics[topic.id] ?? [];
print(completed);
if (completed.contains(quizId)) {
return const Icon(FontAwesomeIcons.checkDouble, color: Colors.green);
} else {
return const Icon(FontAwesomeIcons.solidCircle, color: Colors.grey);
}
}
}
This is the current state of the drawer :
This is the app firestore where I try to access the 'reports' collection.
This is the stream provider I am using:
Any help regarding this issue will be appreciated. Thank You.

How to show progress bar in flutter before loading data

I have a request function and I want to show a progress bar before loading data but idk how to do that. can someone show me an example?
This code calls your function after running the linear progress indicator for a specified time.
The script makes use of no external libraries
import 'dart:async';
import 'package:flutter/material.dart';
class ProgressBarCall extends StatefulWidget {
const ProgressBarCall({ Key? key }) : super(key: key);
#override
_ProgressBarCallState createState() => _ProgressBarCallState();
}
class _ProgressBarCallState extends State<ProgressBarCall> {
double _value = 0;
#override
Widget build(BuildContext context) {
checkIndicator(delay: 2);
return Scaffold(
body: Column(
children: [
LinearProgressIndicator(
backgroundColor: Colors.grey,
color: Colors.green,
minHeight: 5,
value: _value,
),
Expanded(
child: Container(child: Text("Perform function after loading"),),
),
],
),
);
}
void checkIndicator({delay = 2}){
new Timer.periodic(
Duration(milliseconds: delay*100),
(Timer timer){
setState(() {
if(_value == 1) {
timer.cancel();
performFunction();
}
else {
_value = _value + 0.1;
}
});
}
);
}
void performFunction(){
//call your function after the loading
}
}
The performFunction() method can be used to load your data Set the duration of the linear progress indicator by setting the delay in the checkIndicator() method.
You can implement flutter_easyloading package, https://pub.dev/packages/flutter_easyloading
for the progress widget is self you can use [CircularProgressIndicator] https://api.flutter.dev/flutter/material/CircularProgressIndicator-class.html)
for managing the state show loading -> then the actual data -> in case of failure show the error message and stop loading
this can be achieved throw many different ways
1- the easies one FutureBuilder
FutureBuilder<String>(
future: _calculation, // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
List<Widget> children;
if (snapshot.hasData) {
children = <Widget>[
const Icon(
Icons.check_circle_outline,
color: Colors.green,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Result: ${snapshot.data}'),
)
];
} else if (snapshot.hasError) {
children = <Widget>[
const Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
} else {
children = const <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
];
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
);
},
);
or you can use any state management you want
bloc (example)[https://bloclibrary.dev/#/flutterweathertutorial]

How to show the fetched data from api on a button click in flutter?

I want to show the fetched love calculator data after button click but how to visible it? Please answer
import 'dart:io';
import 'package:AllInOneCalci/CustomTextField.dart';
import 'package:AllInOneCalci/Post.dart';
import 'package:AllInOneCalci/customAppBar.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
class LoveCalUI extends StatelessWidget {
#override
Widget build(BuildContext context) {
var AppBarHeight = MediaQuery.of(context).size.height;
return Scaffold(
appBar: customAppBar(
height: (AppBarHeight / 3) * 0.4,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(top: 18.0),
child: Text(
'All In One Cali',
style: TextStyle(
color: Colors.black,
fontSize: 35.0,
fontFamily: 'DancingScript',
fontWeight: FontWeight.bold),
),
),
],
),
),
body: CustomFetchData(),
);
}
}
class CustomFetchData extends StatefulWidget {
#override
_CustomFetchDataState createState() => _CustomFetchDataState();
}
class _CustomFetchDataState extends State<CustomFetchData> {
TextEditingController firstNameController = new TextEditingController();
TextEditingController secondNameController = new TextEditingController();
Future<Post> getData() async {
final response = await http.get(
'https://love-calculator.p.rapidapi.com/getPercentage?fname=aalia&sname=Alice',
headers: {
'x-rapidapi-host': 'love-calculator.p.rapidapi.com',
'x-rapidapi-key':
'84e84770b9msh59a96d8b03cb4aap1615a1jsn1cd0ef******',
});
if (response.statusCode == 200) {
return Post.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load api');
}
}
Widget ErrorDesign() {
return Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
alignment: Alignment.center,
child: Text(
'Error: Kindly Connect to Internet',
style: TextStyle(
color: Colors.redAccent,
fontFamily: 'DancingScript',
fontSize: 40.0,
fontWeight: FontWeight.bold,
),
),
),
);
}
Widget DisplayData(String percentageValue, String result) {
return Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
height: 100.0,
color: Colors.black,
child: Column(
children: [
Text('Percentage is $percentageValue',
style: TextStyle(
color: Colors.white,
)),
Text('Result is: $result',
style: TextStyle(
color: Colors.white,
)),
],
),
),
);
}
Widget FetchedCalculationValues() {
return Column(
children: [
Container(
child: FutureBuilder<Post>(
future: getData(),
builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: CircularProgressIndicator(),
),
);
} else {
if (snapshot.hasError) {
return Container(
child: ErrorDesign(),
);
} else {
return DisplayData(
snapshot.data.percentage, snapshot.data.result);
}
}
})),
],
);
}
#override
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: const EdgeInsets.only(left: 18.0, right: 18.0, top: 15.0),
child: CustomTextField('First Name', "", Colors.cyan,
Colors.cyanAccent, Colors.redAccent, firstNameController),
),
Padding(
padding: const EdgeInsets.only(left: 18.0, right: 18.0),
child: CustomTextField('Second Name', "", Colors.red,
Colors.redAccent, Colors.cyanAccent, secondNameController),
),
Padding(
padding: const EdgeInsets.all(18.0),
child: MaterialButton(
color: Colors.redAccent,
child: Text(
'Result',
style: TextStyle(
color: Colors.white,
),
),
onPressed: () {
FetchedCalculationValues();
print('Fetch Calling');
}),
),
Visibility(
visible: false,
child: FetchedCalculationValues(),
),
],
);
}
#override
// ignore: must_call_super
void initState() {
getData();
}
}
How to make the function for api call visible to the screen after button click.
Also I want to use the text field's values at the place of defalut values
Can you solve my problem? It will be very helpful if you do so. I am a newbie and learning flutter since 15 days. Help me so that I can learn it fast. Also the flutter's community is growing fast so it will be easy for me not to wait for response. Thank You.
I have created simplified, single-screen, app without any extra capabilities to solve exactly your issue. It contains two text fields, two Text widgets to display API results and a floating action button to make request.
Key concepts that you should know to make this code are http requests and asynchronous coding. Those links are good starting points for you to get a sense of what actually happens
To summarize what exactly you need:
You send request asynchronously to the API declaring function with async keyword and await keyword in front of http.get() function. This allows you to wait for the result of the request without freezing the app
When result comes back, the rest of the _getNames() function gets executed, which includes setState(). setState() rebuilds your widget and updates values in Text() widgets
Full code:
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int percentage = 0;
String resultString = "";
Map<String, String> requestHeaders = {
'x-rapidapi-host': 'love-calculator.p.rapidapi.com',
'x-rapidapi-key': 'your API key',
};
final name1Controller = TextEditingController();
final name2Controller = TextEditingController();
void _getNames({String name1, String name2}) async {
final response = await http.get(
'https://love-calculator.p.rapidapi.com/getPercentage?fname=$name1&sname=$name2',
// Send authorization headers to the backend.
headers: requestHeaders,
);
final responseJson = json.decode(response.body);
setState(() {
percentage = int.parse(responseJson['percentage']);
resultString = responseJson['result'];
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: name1Controller,
decoration: InputDecoration(
hintText: "name 1",
),
),
TextField(
controller: name2Controller,
decoration: InputDecoration(
hintText: "name 2",
),
),
SizedBox(
height: 10,
),
Text(
'Your Score is: $percentage',
),
Text(
'$resultString',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_getNames(
name1: name1Controller.text,
name2: name2Controller.text,
);
},
tooltip: 'Increment',
child: Text('Go'),
),
);
}
}

StreamBuilder builds snapshot twice for every one update

I'm trying to build a chat application which displays time along with the message. Here is the main code:
import 'package:flutter/material.dart';
import 'package:flash_chat/constants.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
final _fireStore = Firestore.instance;
FirebaseUser loggedInUser;
class ChatScreen extends StatefulWidget {
static String chatScreen = 'ChatScreenpage1';
#override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
final messageTextEditingController = TextEditingController();
String messageText;
final _auth = FirebaseAuth.instance;
#override
void initState() {
super.initState();
getUserDetail();
}
void getUserDetail() async {
try {
final createdUser = await _auth.currentUser();
if (createdUser != null) {
loggedInUser = createdUser;
}
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: null,
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
_auth.signOut();
Navigator.pop(context);
}),
],
title: Text('⚡️Chat'),
backgroundColor: Colors.lightBlueAccent,
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StreambuilderClass(),
Container(
decoration: kMessageContainerDecoration,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextField(
controller: messageTextEditingController,
onChanged: (value) {
messageText = value;
},
decoration: kMessageTextFieldDecoration,
),
),
FlatButton(
onPressed: () {
messageTextEditingController.clear();
_fireStore.collection('messages').add({
'sender': loggedInUser.email,
'text': messageText,
'time': FieldValue.serverTimestamp()
});
},
child: Text(
'Send',
style: kSendButtonTextStyle,
),
),
],
),
),
],
),
),
);
}
}
class StreambuilderClass extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _fireStore
.collection('messages')
.orderBy('time', descending: false)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.blueAccent,
),
);
}
final messages = snapshot.data.documents.reversed;
List<MessageBubble> messageBubbles = [];
for (var message in messages) {
final messageText = message.data['text'];
final messageSender = message.data['sender'];
final messageTime = message.data['time'] as Timestamp;
final currentUser = loggedInUser.email;
print('check time: $messageTime'); //print(message.data['time']); both gives null
print('check sender: $messageSender');
print('check sender: $messageText');
print(snapshot.connectionState);
final messageBubble = MessageBubble(
sender: messageSender,
text: messageText,
isMe: currentUser == messageSender,
time: messageTime,
);
messageBubbles.add(messageBubble);
}
return Expanded(
child: ListView(
reverse: true,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 20),
children: messageBubbles),
);
});
}
}
class MessageBubble extends StatelessWidget {
final String text;
final String sender;
final bool isMe;
final Timestamp time;
MessageBubble({this.text, this.sender, this.isMe, this.time});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment:
isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: <Widget>[
Text(
' $sender ${DateTime.fromMillisecondsSinceEpoch(time.seconds * 1000)}',
style: TextStyle(color: Colors.black54, fontSize: 12),
),
Material(
color: isMe ? Colors.blueAccent : Colors.white,
borderRadius: isMe
? BorderRadius.only(
topLeft: Radius.circular(30),
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30))
: BorderRadius.only(
topRight: Radius.circular(30),
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30)),
elevation: 6,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 15),
child: Text(
text,
style: TextStyle(
fontSize: 20, color: isMe ? Colors.white : Colors.black),
),
),
),
],
),
);
}
}
But I get this exception for a moment(almost a second) with a red screen and then everything works fine:
By printing the snapshot data field values(The highlighted code in the image) for like 100 times with 100 messages, I realized that the StreamBuilder is sending updated snapshot twice.
(You can see in the output that the first snapshot is with just time field being null and immediately in the second snapshot all values are being present, this happens for every new message I send.)
Everything works as expected in my other app which doesn't use timestamp field in cloud firestore.
My question is shouldn't the StreamBuilder should just send one snapshot for every one update with all the data values being present at once?
Please tell me if I've made a mistake. Any help would be really appreciated!
This is actually expected behaviour for a StreamBuilder. As you can see in this Community Answer:
StreamBuilder makes two build calls when initialized, once for the
initial data and a second time for the stream data.
Streams do not guarantee that they will send data right away so an
initial data value is required. Passing null to initialData throws an
InvalidArgument exception.
StreamBuilders will always build twice even when the stream passed is
null.
So, in order to mitigate that exception and red screen glitch, you will have to take this into consideration and treat this scenario in your code.

Flutter JSON list not returning properly

I've been following this youtube video to help me return data from an online JSON file into a list view. I've altered the code slightly, including a change in URL to the JSON file and due to this, the code now requests different data.
Something tells me it's because the JSON type I want to use isn't compatible with the code I've used, but I don't know why and might be wrong. I use the original 'StarWarsData', 'StarWarsState' that the author of the provided video used just to minimise the differences in my code.
Thanks, Jake
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
void main() {
runApp(MaterialApp(
home: StarWarsData(),
));
}
class StarWarsData extends StatefulWidget {
#override
StarWarsState createState() => StarWarsState();
}
class StarWarsState extends State<StarWarsData> {
final String url = "https://api.coinmarketcap.com/v2/listings/";
List data;
Future<String> getSWData() async {
var res = await http
.get(Uri.encodeFull(url), headers: {"Accept": "application/json"});
setState(() {
var resBody = json.decode(res.body);
data = resBody["data"];
});
return "Success!";
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Star Wars Starships"),
backgroundColor: Colors.deepPurpleAccent,
),
body: ListView.builder(
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, int index) {
return new Container(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Card(
child: Container(
padding: EdgeInsets.all(15.0),
child: Row(
children: <Widget>[
Text("Id: "),
Text(data[index]["id"],
style: TextStyle(
fontSize: 18.0, color: Colors.black87)),
],
)),
),
Card(
child: Container(
padding: EdgeInsets.all(15.0),
child: Row(
children: <Widget>[
Text("Name: "),
Text(data[index]["name"],
style: TextStyle(
fontSize: 18.0, color: Colors.red)),
],
)),
),
Card(
child: Container(
padding: EdgeInsets.all(15.0),
child: Row(
children: <Widget>[
Text("Symbol: "),
Text(data[index]["symbol"],
style: TextStyle(
fontSize: 18.0, color: Colors.black87)),
],
)),
),
],
),
),
);
},
),
);
}
#override
void initState() {
super.initState();
this.getSWData();
}
}
EDIT
The question has now been fixed, but in case anyone was interested, here is the error I was previously encountering:
I/flutter (31850): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY
╞═══════════════════════════════════════════════════════════I/flutter
(31850): type 'int' is not a subtype of type 'String' where I/flutter
(31850): int is from dart:core I/flutter
(31850): String is from dart:core
Issue lies here,
Text(data[index]["id"],
where "id" field is an integer and you are using it directly in place of a String.
Change it to,
Text('${data[index]["id"]}',

Categories

Resources