Future<String> to String into FutureBuilder and Switch statement - flutter

in my application i have a simple method as future which that return String as Future:
Future<String> _decodeLessonUrl(BuildContext context) async {
final ContactData data = await Provider.of<ContactDao>(context).getContacts();
final String encryptedUrl =
'encoded string';
final cryptor = new PlatformStringCryptor();
try {
final String decrypted = await cryptor.decrypt(encryptedUrl, '${data.code}');
return decrypted;
} on MacMismatchException {
return null;
}
}
i want to convert this future to simple String into FutureBuilder and Switch statement:
FutureBuilder<PlayLessonResponse>(
future: _myResponse,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
PlayLessonResponse response = snapshot.data;
switch (response.status) {
case -1: // payment is ok. show play view
final Future<String> decodedLink = _decodeLessonUrl(context);// <-- problem is in this line
return PlayerWidget(link:decodedLink);
}
}
}
return Center(
child: CircularProgressIndicator( ),
);
} ),
i get this error:
error: The argument type 'Future<String>' can't be assigned to the parameter type 'String'.
in that i couldn't use then because this method should be return Widget

For converting Future<String> to String you need to use FutureBuilder.
Replace This:
final Future<String> decodedLink = _decodeLessonUrl(context);
return PlayerWidget(link:decodedLink);
With this:
return FutureBuilder<String>(
future: _decodeLessonUrl(context);
builder: (context, snapshot) {
if(snapshot.hasData){
return PlayerWidget(link:snapshot.data);
}else{
return Center(
child: CircularProgressIndicator( ),
);
}
}
);

Related

get data from json based on index number in flutter

I have a json file from where I am collecting only email addresses, and want to print index number base output like 3rd record's email address to Text widget..
class _HomeScreenState extends State<HomeScreen> {
List<String> list = [];
Future<List<String>> getcomments() async {
Uri url =
Uri.parse('https://jsonplaceholder.typicode.com/posts/1/comments');
var response = await http.get(url);
if (response.statusCode == 200) {
var jsondata = json.decode(response.body);
list.clear();
for (var jdata in jsondata) {
list.add(jdata['email']);
}
}
return list;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('JSON'),
),
body: Center(
child: FutureBuilder(
future: getcomments(),
builder: (context, snapshot) {
return Text(snapshot.data[2].toString());
//here i want only 3rd data(index 2)
},
),
),
);
}
}
Can you try this?
FutureBuilder(
future: getcomments(),
builder: (context, snapshot) {
List<String> data = snapshot.data as List<String>;
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
else {
return Text(data[2]);
}
},
),

How do I incorporate a function where return is a String into a string?

I created a function with a return value of String as follows.
Future<String?> setName() {
String? name='Jon';
return name;
}
Is there any way to incorporate this into the string?
I want to use following situations.
print('Name:${setName}');
or
appBar: AppBar(
title: Text('Name:${setName}'),
When I wrote the above, it unexpectedly output the following
Name:Closure:()=> Future<String?> from Function ...
You could either set a variable to the current state (loading, loaded) and switch the UI accordingly like
return isLoading ? LoadingView() : LoadedView()
or you just pass the future in a FutureBuilder and handle the logic inside it
return FutureBuilder<String>(
future: setName(), // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return LoadedView();
} else {
return LoadingView();
},
}
),
);
It would be better if you use FutureBuilder for future method.
Create a state future variable.
class _TestXState extends State<TestX> {
Future<String?> setName() async {
String? name = 'Jon';
await Future.delayed(Duration(seconds: 2));
return name;
}
late final nameFuture = setName();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: FutureBuilder(
future: nameFuture,
builder: (context, snapshot) {
if (snapshot.hasData) return Text("${snapshot.data}");
return Text("....");
},
),
),
);
}
}

FutureBuilder not populating value

In my main.dart I have an async function to get data from an URL.
getShopLength() async {
final queryParameters = {
'api_key': '123',
'user_id': '123',
'lat': '123',
'long': '123',
'km': '123',
};
var response = await http.get(Uri.https('google.de','getSth', queryParameters));
var jsonData = jsonDecode(response.body);
List<Shops> shops = [];
for(var x in jsonData) {
Shops shop = Shops(x['name'], x['slogan']);
shops.add(shop);
}
return shops.length;
}
In my home.dart I want to get the value from getShopLength() but I always get the error: type 'Future<dynamic> is not a subtype of type 'Future<String>?'
I try to save the return value into valueShop and pass it to buildRestaurantRow('Top Angebote', context, valueShop)
home.dart
#override
Widget build(BuildContext context) {
var valueShop = "0";
FutureBuilder<String>(
future: getShopLength(),
builder: (context, snapshot) {
if (snapshot.hasData) {
valueShop = snapshot.data;
}
return CircularProgressIndicator();
}
);
return Scaffold(
appBar: buildSearchBar(context),
body: Padding(
padding: const EdgeInsets.fromLTRB(10.0, 0, 10.0, 0),
child: ListView(
children: <Widget>[
SizedBox(height: 20.0),
buildRestaurantRow('Top Angebote', context, valueShop),
SizedBox(height: 10.0),
buildRestaurantList(context),
SizedBox(height: 10.0),
buildCategoryRow('Nach Kategorie', context),
SizedBox(height: 10.0),
buildCategoryList(context),
SizedBox(height: 20.0),
buildCategoryRow('Deine Favoriten', context),
SizedBox(height: 10.0),
buildFriendsList(),
SizedBox(height: 30.0),
],
),
),
);
}
What am I missing?
So the problem lies here:
FutureBuilder<String>(
future: getShopLength(),
Your future builder has a type of string, which means that the future should be of type Future<String>, but when you declared the function getShopLength, you did this:
getShopLength() async {
You did not give it a return type, because of that, the default return type is Future<dynamic>.
The obvious solution is giving the function a return type, but you have another problem:
The futurebuilder expects a string value, but the function returns a number, so which is it?
If you want to return a string of the length, you can just do this:
Future<String> getShopLength() async {
...
return shops.length.toString();
}
Or you can also change the futurebuilder's value to be int:
Future<int> getShopLength() async {
...
return shops.length;
}
...
int valueShop = 0;
FutureBuilder<int>(
future: getShopLength(),
builder: (context, snapshot) {
if (snapshot.hasData) {
valueShop = snapshot.data;
}
return CircularProgressIndicator();
},
);
Side note:
Ok, I have a couple of things to mention about your code:
First of all, on your getShopsLength function, you have two lists, jsonData and shops, you don't actually need both, you can just use one:
var jsonData = jsonDecode(response.body);
return jsonData.length // no need for the shops list.
Second of all, what's up with your builder code?? You first declare a FutureBuilder, but then completely ignore it and move on to a Scaffold widget? I believe the scaffold code should be inside the future builder, as it stands, you will never see the circular progress indicator:
From:
var valueShop = '0';
FutureBuilder<String>(
future: getShopLength(),
builder: (context, snapshot) {
if (snapshot.hasData) {
valueShop = snapshot.data;
}
return CircularProgressIndicator();
}
);
return Scaffold(...);
To:
return FutureBuilder<String>(
future: getShopLength(),
builder: (context, snapshot) {
if (snapshot.hasData) {
var valueShop = snapshot.data;
return Scaffold(...);
}
return CircularProgressIndicator();
}
);

How to display SharedPreferences value in Text widget in flutter?

The task is to get value from SharedPrefrences and display it in the Text widget.
Here I tried to store the value in the variable _userCurrency and display it in ListTile. The problem seems that the ListTile loads quickly with the value "null".
Even getUserCurrencySymbol() isn't returning any value. I have already tried
return MySharedPreferences.instance.getUserCurrencyValue('userCurrency'); and other possible solutions.
menu.dart
late String _userCurrency;
getUserCurrencySymbol().then((value) {_userCurrency = value.toString();});
return StatefulBuilder(
builder: (BuildContext context, void Function(void Function()) setState) {
return ListView(
children: [
ListTile(title: Text(_userCurrency)),
]
) //ListView
},
); //Stateful builder
controller.dart
Future<String> getUserCurrencySymbol() async {
return MySharedPreferences.instance.getUserCurrencyValue('userCurrency').then((value) {return value.toString();});
}
class MySharedPreferences {
MySharedPreferences._privateConstructor();
static final MySharedPreferences instance = MySharedPreferences._privateConstructor();
setUserCurrencyValue(String key, String value) async {
SharedPreferences instance = await SharedPreferences.getInstance();
instance.setString(key, value);
}
getUserCurrencyValue(String key) async {
SharedPreferences instance = await SharedPreferences.getInstance();
return instance.getString(key) ?? "Bitcoin";
}
You should use setState to update the ui when the data is loaded.
getUserCurrencySymbol().then((value) {
setState((){
_userCurrency = value.toString();
});
});
You can use FutureBuilder to load data and handle loading/error states
FutureBuilder<String>(
future: getUserCurrencySymbol(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if(snapshot.hasError) {
//fixme just to check an error
print("Error: ${snapshot.error}");
return Text("Error");//or what you want
}
if (!snapshot.hasData) {
return CircularProgressIndicator();//or what you want
}
return ListView(
children: [
ListTile(title: Text(snapshot.data)),
]
);
},
)
And try to change getUserCurrencySymbol();
Future<String> getUserCurrencySymbol() {
return MySharedPreferences.instance.getUserCurrencyValue('userCurrency');
}

snapshot.data is null in Flutter

My snapshot.data is null. When I print the response it is displaying the retrieved data. But still snapshot.data is null.
Future _getUsers() async {
var data = await http.post("http://10.0.2.2/Flutter/abreport.php", body: {
{
"date": mydt,
});
var jsonData = json.decode(data.body); //edited
print(jsonData); // the data is printing here
return jsonData;
}
}
FutureBuilder(
future: _getUsers(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
debugPrint(snapshot.data);
if (snapshot.data == null) {
return Container(
child: Center(
child:Text("no data"),
)
);
} else {
//some code
}
)
You should use the format given in the documentation for FutureBuilder. You're not checking for the state of the future, so when the FutureBuilder is first built, it will display "no data". You haven't implemented your else branch, so by the time you have data, your build will probably not refresh anyway. Try this code instead:
FutureBuilder(
future: _getUsers(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data == null) {
return Text('no data');
} else {
return Text('data present');
}
} else if (snapshot.connectionState == ConnectionState.error) {
return Text('Error'); // error
} else {
return CircularProgressIndicator(); // loading
}
}
)
with Flutter 2.2, this one returns an error
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data,);
Error: The argument type 'String?' can't be assigned to the parameter type 'String' because 'String?' is nullable and 'String' isn't.
return Text(snapshot.data,);
but this one dosen't
builder: (BuildContext context, AsyncSnapshot snapshot) {
When similar things happen, take the type "var" not "String" or other non-nullable type.
(If it was not Flutter, the compilers will do?)
Since i cannot see your complete code, i am assuming you are parsing your json data incorrectly after receiving it inside FutureBuilder. Below is an example which is similar to what you are doing. This example retrieves Date json data and displays using FutureBuilder,
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(new MyApp());
}
class MyApp extends StatefulWidget {
#override
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
child: FutureBuilder(
future: _getDate(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return Text('Date: ' + snapshot.data['date']
+ '\nMilliseconds Since Epoch: ' + snapshot.data['milliseconds_since_epoch'].toString()
+ '\nTime: ' + snapshot.data['time'],
style: TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold, color: Colors.grey));
} else {
return Center(child: CircularProgressIndicator());
}
},
))
]))));
}
Future _getDate() async {
var data = await http.post("http://date.jsontest.com/");
var jsonData = json.decode(data.body);
print(jsonData);
return jsonData;
}
}
Test screenshot:
Hope this helps.
Because your async function doesnt return anything..
Change it like this:
Future _getUsers() async {
return await http.post("http://10.0.2.2/Flutter/abreport.php", body: {
{
"date": mydt,
});
var jsonData = json.decode(data.body); //edited
print(jsonData); // the data is printing here
return jsonData;
}
}