Get Future value without Futurebuilder - flutter

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(),
)
],
),
),
);
}
}

Related

Display data from Firebase in async - Flutter

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});

Waiting for Async Data in InitState

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());
},
);
}

How can i used the multi future in FutureBuilder?

Begins an asynchronous calls the function and multiple.
However, the response to the second call is always null.
I want to update it to the screen when I get all the results.
sometimes invoked Error msg like this :
type 'List' is not a subtype of type 'Map<dynamic, dynamic>'
class _HomePageState extends State<Home> {
final _formKey = GlobalKey<FormState>();
final _formKey2 = GlobalKey<FormState>();
aboutRes about; // delete
var _callStack = [Gateway.Instance.about(), Wifi.Instance.ssidInfo(0)];
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body : Padding(
padding: const EdgeInsets.all(15.0),
child: Column(children: [
Expanded(
child: FutureBuilder(
future : Future.wait(_callStack),
key : _formKey,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Invoked Error is ${snapshot.error}');
} else if (snapshot.hasData) {
return ListView (
padding: const EdgeInsets.all(0.8),
children: [
Container(
child : Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
InformationItem(about: snapshot.data[0]),
WirelessItem(ssid: snapshot.data[1]),
],
),
)
]
);
} else {
return CircularProgressIndicator();
}
}
)
),
]),
)
);
}
}
Future<aboutRes> about() async {
aboutRes res;
ApiResponse response = await get(GATEWAY_ABOUT);
// for jsonSerialization
Map resMap = jsonDecode(response.body);
res = aboutRes.fromJson(resMap);
return res;
}

Unable to display string from snapshot

I would like to get data from firestore and display in the text but an eror has popup.
Thar error say type '_BroadcsastStream' is not a subtype of type 'String'.
Class i call the method
void main() => runApp(MaterialApp(
home : profUser(),
));
class profUser extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home : new profiUser(),
);
}
}
class profiUser extends StatefulWidget {
#override
_profiUserState createState() => _profiUserState();
}
class _profiUserState extends State<profiUser> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.indigo,
appBar: AppBar(
title: Text('Profile'),
actions: <Widget>[
IconButton(
icon: Icon(choices[1].icon),
onPressed: (){
logOut();
Navigator.push(context,MaterialPageRoute(builder: (context)
=> myLogin()));
},
),
],
),
body: Column(
children: <Widget>[
userDetail(),
],
),
);
}
}
Class to display text based on the data from firestore
class userDetail extends StatelessWidget{
#override
Widget build(BuildContext context){
return new StreamBuilder(
stream: UniQuery().getUserDetail(),
builder: (BuildContext context, snapshot){
if(!snapshot.hasData)
return new Text('Loading..... Please wait');
var userDocument = snapshot.data;
return new Column(
children: <Widget>[
Text('Name: ' + userDocument['name']),
Text('Age: ' + userDocument['age'],toString()),
Text('Address: ' + userDocument['address']),
Text('Result: ' + userDocument['result']),
],
);
}
);
}
}
Below the void that use in above code to get data from firestore
var userID;
Future<String> getCurrentUser() async{
final FirebaseUser user = await FirebaseAuth.instance.currentUser();
// return uID != null ? uID : null;
final String uID = user.uid.toString();
return uID;
}
setUserDetail() async{
userID = await getCurrentUser();
}
The problem is inside getUserDetail() you are passing an async function to documents(), so that function returns a Future. Before calling documents() you should first get the string, waiting the async call to finish, and then pass the string to documents().

FLutter : The method '[]' was called on null when iterating list

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(),
),
)
);
}