This is the source code I have till now. Can you tell me what is wrong and why I am getting this error?
Any help would be appreciated. Thanks!
The error is:
error in Data[0] it show Flutter : The method '[]' was called on null when iterating list import 'package:flutter/material.dart';
class MyGetHttpDataState extends State<MyGetHttpData> {
final String url = "*******";
List data, a; int index; // Function to get the JSON data
Future<String> getJSONData() async {
var response = await http.get(url);
print(response.body);
setState(() {
json.decode(response.body);
data = dataConvertedToJSON['data']; index = 0;
});
return "Successfull";
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar( title: new Text('List Test'), ),
body: new Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
for (var name in data[0]['INCI']) Text(name)
], ), ), ));
}
#override
void initState() {
super.initState();
this.getJSONData();
}
}
Just change your code to this!
Future<String> getJSONData() async {
var response = await http.get(url);
setState(() {
var dataConvertedToJSON = json.decode(response.body);
data = dataConvertedToJSON['data'];
data = data[0]['INCI'];
});
return "Successfull";
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar( title: new Text('List Test'), ),
body: new Center(
child: data != null ? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
for (var name in data) Text(name)
],
) : new CircularProgressIndicator(),
),
)
);
}
Related
I want to create a profil page where I just display informations from the user, but I have trouble to reach the data. When I want to use my variable user it display 'Instance of Future<Map<String, dynamic>>'
If I put the 'Widget build' in async I have an error message who told me : ProfileScreen.build' ('Future Function(BuildContext)') isn't a valid override of 'StatelessWidget.build' ('Widget Function(BuildContext)').
class ProfileScreen extends StatelessWidget {
ProfileScreen({super.key});
#override
Widget build(BuildContext context) {
final user = displayUser();
return Scaffold(
appBar: AppBar(
title: Text('Profile'),
),
body: Align(
alignment: Alignment.topLeft,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Align(
alignment: Alignment.topLeft,
child: Column(children: [
Text('Prénom :${user}\nNom :\nEmail :',
textWidthBasis: TextWidthBasis.longestLine),
]),
)
]),
),
persistentFooterButtons: [
SignOutButton(),
BottomNavBar(),
]);
}
// Get user informations
Future<Map<String, dynamic>> displayUser() async {
final User? currentUser = FirebaseAuth.instance.currentUser;
late final userUid = currentUser?.uid;
late final ref = FirebaseDatabase.instance.ref();
final resSnapshot = await ref.child('/utilisateur/' + userUid!).get();
final Map<String, dynamic> user = {};
if (resSnapshot.exists) {
user['id'] = userUid;
for (var value in resSnapshot.children) {
String key = value.key as String;
var val = value.value;
user[key] = val;
}
} else {
print('No data available.');
}
print(user); // This print display exactly the informations I want.
return user;
}
}
Thanks for your help.
Your displayUser is async function and you can't call it inside build method, you need to use FutureBuilder like this:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Profile'),
),
body: FutureBuilder<Map<String, dynamic>>(
future: displayUser(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading....');
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
Map<String, dynamic> user = snapshot.data ?? {};
return Align(
alignment: Alignment.topLeft,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Align(
alignment: Alignment.topLeft,
child: Column(
children: [
Text(
'Prénom :${user}\nNom :\nEmail :',
textWidthBasis: TextWidthBasis.longestLine,
),
],
),
)
],
),
);
}
}
},
),
persistentFooterButtons: [
SignOutButton(),
BottomNavBar(),
],
);
}
You can customize loading and error state to what you want.
You can load the user in the initstate and then set user using setstate
class ProfileScreen extends StatefulWidget {
const ProfileScreen({super.key});
#override
State<ProfileScreen> createState() => _ProfileScreenState();
}
class _ProfileScreenState extends State<ProfileScreen> {
Map<String, dynamic>? user;
#override
void initState() {
final User? currentUser = FirebaseAuth.instance.currentUser;
late final userUid = currentUser?.uid;
late final ref = FirebaseDatabase.instance.ref();
final resSnapshot = await ref.child('/utilisateur/' + userUid!).get();
Map<String, dynamic> temp = {};
if (resSnapshot.exists) {
temp['id'] = userUid;
for (var value in resSnapshot.children) {
String key = value.key as String;
var val = value.value;
temp[key] = val;
}
} else {
print('No data available.');
}
print(temp);
setState((){
user =temp
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child:
user != {} ? Text(user.toString()!) : const CircularProgressIndicator()),
);
}
}
change StatelessWidget to StatefulWidget because userInteract on profileScreen,
UserInteraction changes will show on firebase.
class ProfileScreen extends StatefulWidget{
ProfileScreen({super.key});
i am new at flutter, so i tried to implement carousel slider with images, i receive an List with my model from server and i created widget but it shows only 1 item from 18... I mean it always show 1 item, but all list is passed
But if i make hot reload then i receive all items, i hope i could explain... my dart code
import 'dart:convert';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:vltest/Models/_easyloaderslist.dart';
import 'Models/_workers.dart';
import 'Widgets/navigation_drawer_widget.dart';
import 'database.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;
late List<EasyLoadersList> imgList = List.empty();
class Landing extends StatefulWidget {
#override
_LandingState createState() => _LandingState();
}
Future<List<EasyLoadersList>> _getLoaders(Workers workers) async {
final response = await http.get(
Uri.parse(
'http://url'),
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer ${workers.token}"
});
if (response.statusCode == 200) {
Iterable l = json.decode(response.body);
List<EasyLoadersList> loaders = List<EasyLoadersList>.from(
l.map((model) => EasyLoadersList.fromJson(model)));
return loaders;
} else {
throw Exception('Failed to load album');
}
}
List<T> map<T>(List list, Function handler) {
List<T> result = [];
for (var i = 0; i < list.length; i++) {
result.add(handler(i, list[i]));
}
return result;
}
showWorkerDialog(BuildContext context, Workers album) {
// set up the button
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () {
Navigator.pop(context);
},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text(album.name),
content: Text("Hi, ${album.name}"),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
class _LandingState extends State<Landing> {
String _username = "";
late List<EasyLoadersList> loaders = List.empty();
int _current = 0;
#override
void initState() {
super.initState();
_loadUserInfo();
}
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: NavigationDrawerWidget(),
appBar: AppBar(
title: Text('User info'),
),
body: RefreshIndicator(
onRefresh: () async {
_loadUserInfo();
},
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CarouselSlider.builder(
itemCount: imgList.length,
itemBuilder: (context, index, realIndex) {
if (imgList.length != 0) {
return buildImage(imgList[index]);
} else {
return loadingData(context);
}
},
options: CarouselOptions(height: 500),
),
]),
),
),
);
}
Widget buildImage(EasyLoadersList loadersList) => Column(
mainAxisSize: MainAxisSize.max,
children: [
AspectRatio(
aspectRatio: 1,
child: Image.network(
loadersList.url,
fit: BoxFit.fill,
),
),
const SizedBox(
height: 30,
),
Text("Address :" + loadersList.shopAddress),
Text("Serial:" + loadersList.serialNumber),
Text("Hours :" + loadersList.currentMotoHours),
Text("Current:" + loadersList.currentMotoHoursUntilTO),
Text("Next:" + loadersList.remainsMotoHoursUntilTO),
Text("Last Use:" + loadersList.lastMotoHoursEditDate),
],
);
Widget loadingData(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(
'Loading...',
style: Theme.of(context).textTheme.headline6,
),
CircularProgressIndicator(
semanticsLabel: 'Loading...',
),
],
),
),
);
}
Future<void> _loadUserInfo() async {
Workers workers = await DBProvider.db.getWorkerInfo();
final prefs = await SharedPreferences.getInstance();
showWorkerDialog(context, workers);
imgList = await _getLoaders(workers);
}
}
Cant see any setState to update the UI. try adding setState on end of refresh like.
onRefresh: () async {
await _loadUserInfo();
setState((){});
},
And on initState
_loadUserInfo().then((value) {setState((){})}):
Or
Future<void> _loadUserInfo() async {
.....
imgList = await _getLoaders(workers);
setState((){});
}
I need to get data from a Future to a Stateful widget before it displays on startup. I have tried async/await, FutureBuilder, and the Sync package implementing a WaitGroup within the initState method; however, nothing I do waits for the data to return from the Future before it renders the screen.
In the below examples, I have a simple String strName that I initialize to "Default Name" that I am using for testing and displaying in the Scaffold. It only displays the initialized "Default Name," and not the name returned from the Future. The closest I got was using a FutureBuilder, at least it updated the screen after the initialized "Default Name" was shown. However, I need to get the data prior to the screen rendering. Does anyone have any ideas?
Here's an example of what I tried with Sync WaitGroup:
class _MyHomePageState extends State<MyHomePage> {
String strName = "Default Name";
Future<String> _getName() async {
var name = await Future<String>.delayed(const Duration(seconds: 5), () => "New Name");
return name;
}
#override
void initState() {
WaitGroup wg = WaitGroup();
wg.add(1);
Future<String> futureName = _getName();
futureName.then(
(value) {
strName = value;
wg.done();
},
);
wg.wait();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(strName),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
strName,
style: Theme.of(context).textTheme.headline4,
),
],
),
),
);
}
}
This is what my async/await method looked like:
class _MyHomePageState extends State<MyHomePage> {
String strName = "Default Name";
Future<String> _getName() async {
var name = await Future<String>.delayed(const Duration(seconds: 5), () => "Jimbo");
return name;
}
#override
void initState() {
Future<String> futureName = _getName();
futureName.then(
(value) {
strName = value;
},
);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(strName),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
strName,
style: Theme.of(context).textTheme.headline4,
),
],
),
),
);
}
}
I've never worked with a language where there asynchronous is the default structure of so many parts. How do you deal with making async synchronous in Dart? I haven't even got into the SQLite and HTTP part of it, and it is killing me. I've been at it for four days and got so frustrated I almost broke a keyboard yesterday.
The best is to use a loading screen while fetching your data
and use snapshot.data
full implementation using FutureBuilder:
class _MyHomePageState extends State<MyHomePage> {
String strName = "Default Name";
Future<String> _getName() async {
var name = await Future<String>.delayed(
const Duration(seconds: 5), () => "New Name");
return name;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(strName),
),
body: FutureBuilder<String>(
future: _getName(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
snapshot.data!,
style: Theme.of(context).textTheme.headline4,
),
],
);
}
return Center(
child: CircularProgressIndicator(),
);
}),
);
}
}
This is really a bad practice
but if you really need to resolve some future data before the app renders you can use the void main() method.
void main()async {
Future<String> futureName = _getName();
futureName.then(
(value) {
strName = value;
runApp(MyApp());
},
);
}
I want to get the value of a future function (without futurebuilder), in which I load a json file, I put this value in a text widget but it returns me this message "Instance of 'Future void'" I don't know why .
helperLoadJson.dart
//Load Json
Future<String> _loadAStudentAsset() async {
return await rootBundle.loadString('assets/Copie.json');
}
//Load Response
Future loadStudent([int index]) async {
String jsonString = await _loadAStudentAsset();
final jsonResponse = json.decode(jsonString);
QuotList quotList = QuotList.fromJson(jsonResponse);
return quotList.quots[0].country;
}
main.dart
class _MyHomePageState extends State<MyHomePage> {
//Get Future from helperLoadJson.dart
Future<void> getLoadStudent() async {
final String myQuot = await loadStudent();
print(myQuot); // OK , return me good value
}
#override
Widget build(BuildContext context) {
print('getLoadStudent : ${getLoadStudent()}'); // return " Instance of 'Future<void>' "
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'${getLoadStudent()}', // return " Instance of 'Future<void>' "
),
Container(
// child: projectWidget(),
)
],
),
),
);
}
}
I am trying to return a ListView.builder but it doesn't seem to happen with the code below. I have just started to learn to use flutter and I am trying to implement flutter_insta before moving to the actual API. With the code below I receive the first debug message to the console but the second one never comes. Does anyone have any idea why does this happen? I don't get any error messages either.
class _HomePageState extends State<HomePage> {
String _username = "xxx";
FlutterInsta flutterInsta = FlutterInsta();
List<String> images = new List<String>();
bool pressed = false;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Feed preview'),
),
body: homePage(),
);
}
Widget homePage(){
return Center(
child: Column(
children: [
RaisedButton(
child: Text("Load photos"),
onPressed: () async {
setState(() {
pressed = true;
printDetails(_username);
});//get Data
},
),
]
)
);
}
Future printDetails(String username) async {
await flutterInsta.getProfileData(username);
setState(() {
this.images = flutterInsta.feedImagesUrl;
});
_buildSuggestions();
}
Widget _buildSuggestions() {
print("debug");
return ListView.builder(
itemBuilder: /*1*/ (context, i) {
print("debug1");
if (i.isOdd) return Divider(); /*2*/
final index = i ~/ 2; /*3*/
return _buildRow(images[index]);
});
}
Widget _buildRow(String url) {
print("moi");
return ListTile(
trailing: Image.network(url)
);
}
}
_buildSuggestions have to be used somewhere in the widget tree.
class _HomePageState extends State<HomePage> {
String _username = "xxx";
FlutterInsta flutterInsta = FlutterInsta();
List<String> images = new List<String>();
bool pressed = false;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Feed preview'),
),
body: homePage(),
);
}
Widget homePage(){
return Center(
child: Column(
children: [
Expanded(child: _buildSuggestions()),
RaisedButton(
child: Text("Load photos"),
onPressed: () async {
setState(() {
pressed = true;
printDetails(_username);
});//get Data
},
),
]
)
);
}
Future printDetails(String username) async {
await flutterInsta.getProfileData(username);
setState(() {
this.images = flutterInsta.feedImagesUrl;
});
}
Widget _buildSuggestions() {
print("debug");
return ListView.builder(
itemBuilder: /*1*/ (context, i) {
print("debug1");
if (i.isOdd) return Divider(); /*2*/
final index = i ~/ 2; /*3*/
return _buildRow(images[index]);
});
}
Widget _buildRow(String url) {
print("moi");
return ListTile(
trailing: Image.network(url)
);
}
}
You need to render to _buildSuggestion in widget tree first.
You need to put itemCount to ListView.Builder
Checkout: https://api.flutter.dev/flutter/widgets/ListView/ListView.builder.html