How to return value on async function in flutter? - dart

This is my code
SharedPreferences sharedPreferences;
token() async {
sharedPreferences = await SharedPreferences.getInstance();
return "Lorem ipsum dolor";
}
When I print, I got this message on debug console
Instance of 'Future<dynamic>'
How I can get string of "lorem ipsum..." ? thank you so much

token() is async which means it returns Future. You can get the value like this:
SharedPreferences sharedPreferences;
Future<String> token() async {
sharedPreferences = await SharedPreferences.getInstance();
return "Lorem ipsum dolor";
}
token().then((value) {
print(value);
});
But there is a better way to use SharedPreferences. Check docs here.

In order to retrieve any value from async function we can look at the following example of returning String value from Async function. This function returns token from firebase as String.
Future<String> getUserToken() async {
if (Platform.isIOS) checkforIosPermission();
await _firebaseMessaging.getToken().then((token) {
return token;
});
}
Fucntion to check for Ios permission
void checkforIosPermission() async{
await _firebaseMessaging.requestNotificationPermissions(
IosNotificationSettings(sound: true, badge: true, alert: true));
await _firebaseMessaging.onIosSettingsRegistered
.listen((IosNotificationSettings settings) {
print("Settings registered: $settings");
});
}
Receiving the return value in function getToken
Future<void> getToken() async {
tokenId = await getUserToken();
}
print("token " + tokenId);

Whenever the function is async you need to use await for its response otherwise Instance of 'Future' will be output

Related

Dart future with non async function

I am creating a function for firebase phone auth using Dart. There are two functions getCredential and then signIn. When using a try/catch block I am unsure of how this should be coded. Should the non-async function getCredential be outside of the try/catch block or inside?
Should it be coded as:
// Sign in with phone
Future signInWithPhoneNumber(String verificationId, String smsCode) async {
AuthCredential credential = PhoneAuthProvider.getCredential(
verificationId: verificationId,
smsCode: smsCode,
);
try {
AuthResult result = await _auth.signInWithCredential(credential);
FirebaseUser user = result.user;
return user;
} catch (e) {
print(e.toString());
return null;
}
}
Or should it be coded like this?
// Sign in with phone
Future signInWithPhoneNumber(String verificationId, String smsCode) async {
try {
AuthCredential credential = PhoneAuthProvider.getCredential(
verificationId: verificationId,
smsCode: smsCode,
);
AuthResult result = await _auth.signInWithCredential(credential);
FirebaseUser user = result.user;
return user;
} catch (e) {
print(e.toString());
return null;
}
}
If coded as the second option does the try/catch only work with the async function or both. For example, if the getCredential function generated an error would it be caught in the catch block?
Yes the catch will handle anything that throws in your try block, it's not async specific. To confirm this you could write a function that gets called at the beginning of the try for example:
// this is a function that throws
void doSomething(String param) {
if (param == null) {
throw FormatException('param can not be null');
}
}
Future signInWithPhoneNumber(String verificationId, String smsCode) async {
try {
doSomething(null); // this will be caught
AuthCredential credential = PhoneAuthProvider.getCredential(
verificationId: verificationId,
smsCode: smsCode,
);
AuthResult result = await _auth.signInWithCredential(credential);
FirebaseUser user = result.user;
return user;
} catch (e) {
print(e.toString()); // this prints 'FormatException: param can not be null'
return null;
}
}
So async is not related to whether your function will be caught or not so it's better to use the second option.

How to display variable from json return in text

String empName;
Future<List> getUserData() async{
final response = await http.post("http://172.16.161.34:8080/ebs/cfs/android_test_app/accessfile.php?q=getUserData",body:{
"emp_id": widget.empId,
});
var dataUser = jsonDecode(response.body);
empName = dataUser[0]['name'];
return null;
}
How to display the variable "empName" in line 2 to line 70 "child: Text('')"
Full code on Pastebin
Try this way.. make pojo class for response data like this way..
class UserData {
final int albumId;
final int id;
final String title;
final String url;
final String thumbnailUrl;
UserData({this.albumId, this.id, this.title, this.url, this.thumbnailUrl});
factory UserData.fromJson(Map<String, dynamic> json) {
return new UserData(
albumId: json['albumId'],
id: json['id'],
title: json['title'],
url: json['url'],
thumbnailUrl: json['thumbnailUrl']);
}
}
make method for api call..
Future<UserData> fetchData() async {
var result = await get('https://jsonplaceholder.typicode.com/photos');
if (result.statusCode == 200) {
return UserData.fromJson(json.decode(result.body));
} else {
// If that response was not OK, throw an error.
throw Exception('Failed to load post');
}
}
after that make global object that fetch data..
Future<UserData> userDataList;
on Button click ..
userDataList = fetchData();
after that you want to print data..
userDataList.then((userData){
print(userData.title);
});
First of all you getUserData() function never returns anything. It seems like you only need the name so this function could look like this:
Future<String> getUserData() async{
final response = await http.post("http://172.16.161.34:8080/ebs/cfs/android_test_app/accessfile.php?q=getUserData",body:{
"emp_id": widget.empId,
});
var dataUser = jsonDecode(response.body);
return dataUser[0]['name'];
}
Then to set the empName variable you should use setState().
So change your afterFirstLayout() method to this:
#override
void afterFirstLayout(BuildContext context) async {
// Calling the same function "after layout" to resolve the issue.
getUserData().then( (userName) {
setState(() {
empName = userName;
});
});
}
Also you seem to want to reload the name once you press the IconButton.
So you might want to override your code with this:
IconButton(icon: Icon(Icons.shopping_cart),
onPressed:() {
getUserData().then( (userName) {
setState(() {
empName = userName;
});
});
},
),

Flutter Shared Preferences Auth FIle

I'm trying to write an auth file, with a list of finals with shared preferences values in it. I could import that auth file in my other files and i could get like the name or email without importing shared preferences in every file.
It would probably look way smoother and cleaner.
I thought something like this would have worked but it didn't
/// ------------Auth------------ ///
final email = getEmail();
getEmail() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getString('email');
}
Does anybody have any idea how to do this?
Greetings,
Jente
I assume you want to use the method in multiple files. The problem with your code is that the getEmail method is marked async that means it will have to return a Future. Think about it like this, when you mark a method as async it means it will return something (or finish executing) in the near future. When ? Well you don't know exactly when, so you'll need to get "notified" when the method is "done", that's why you'll use a Future. Something like this:
Future<String> getEmail() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getString('email');
}
class ThisIsTheClassWhereYouWantToUseTheFunction {
//let's say you have a method in your class called like the one below (it can be any other name)
void _iNeedTheEmailToPrintIt() {
//this is the way you can call the method in your classes, this class is just an example.
getEmail().then((thisIsTheResult){ // here you "register" to get "notifications" when the getEmail method is done.
print("This is the email $thisIsTheResult");
});
}
}
you can define a class Auth or much better a scoped_model.
Here's a class implementation
class Auth {
get email() {
final SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getString('email');
}
set email(String em) {
final SharedPreferences prefs = await SharedPreferences.getInstance();
pref.setString('email', em);
}
}
and now you can call it in your widgets :)
Try this;
make dart file (Filename and Class Name ShareUtils)
add follow Code
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:async';
class ShareUtils {
static ShareUtils _instance;
SharedPreferences ShareSave;
factory ShareUtils() => _instance ?? new ShareUtils._();
ShareUtils._();
void Instatce() async {
ShareSave = await SharedPreferences.getInstance();
}
Future<bool> set(key, value) async {
return ShareSave.setString(key, value);
}
Future<String> get(key) async {
return ShareSave.getString(key);
}
}
2.Add main.dart
class MyApp extends StatelessWidget {
static ShareUtils shareUtils;
#override
Widget build(BuildContext context) {
ThemeData mainTheme = new ThemeData(
);
shareUtils = new ShareUtils();
shareUtils.Instatce();
MaterialApp mainApp = new MaterialApp(
title: "Your app",
theme: mainTheme,
home: new SplashPage(),
debugShowCheckedModeBanner: true,
routes: <String, WidgetBuilder>{
"RegisterPage": (BuildContext context) => new RegisterPage(),
"HomePage": (BuildContext context) => new HomePage(),
},
);
return mainApp;
}
}
3.SET
void UserInfo(code, token) async{
await MyApp.shareUtils.set("token", token);
await MyApp.shareUtils.set("code", code);
await Navigator.of(context).pushNamed("HomePage");
}
4.GET
Future NextPage() async {
MyApp.shareUtils.get("token").then((token) {
print(token);
if (token == null || token == "") {
Navigator.of(context).popAndPushNamed("RegisterPage");
} else {
Navigator.of(context).popAndPushNamed("HomePage");
}
});
}
Hope to help.

Flutter - How to get value from shared preferences in a non-async method

I am trying to get some values saved in the SharedPreferences from a getter method of a class. But SharedPreferences.getInstance() returns a Future. Is there a way to obtain the SharedPreferences object in a non-async getter methods, for example:
import 'package:shared_preferences/shared_preferences.dart';
class MyClass {
get someValue {
return _sharedPreferencesObject.getString("someKey");
}
}
Is there something in Dart that is similar to .Result property in C#, for example getSomethingAsync().Result (https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1.result?view=netframework-4.7.2)?
You can use FutureBuilder()
SharedPreferences sharedPrefs;
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _getPrefs(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return YourFinalWidget();
}
return CircularProgressIndicator(); // or some other widget
},
);
}
Future<void> _getPrefs() async{
sharedPrefs = await SharedPreferences.getInstance();
}
You can do it in initState() and after this call setState() to update your build() method. Other way is to use FutureBuilder()
SharedPreferences sharedPrefs;
#override
void initState() {
super.initState();
SharedPreferences.getInstance().then((prefs) {
setState(() => sharedPrefs = prefs);
});
}
I suggest you use GetStorage
https://pub.dev/packages/get_storage
you will be able to get values without awaiting for them
main.dart
await GetStorage.init();
runApp(MyApp());
storage.dart
static bool isFirstOpen() {
final box = GetStorage();
return box.read("isFirstOpen") ?? true;
}
static setFirstOpen(bool isopen) {
final box = GetStorage();
box.write("isFirstOpen", isopen);
}
You can do something like this
Create a separate shared preferences service
Take in the SharedPreferences value in the constructor
You can then do get call without async, await
Example
class SharedPreferencesService {
final SharedPreferences _prefs;
const SharedPreferencesService(this._prefs);
Future<void> setString(String key, String value) async {
await _prefs.setString(key, value);
}
String? getString(String key) {
if (containsKey(key)) {
return _prefs.getString(key);
} else {
return null;
}
}
bool containsKey(String key) {
return _prefs.containsKey(key);
}
}
The only async call in SharedPreferences is to get the initial instance. This can be reused across your application. main can be async. So you can just await the SharedPreferences instance in main:
late SharedPreferences prefs;
main() async {
prefs = await SharedPreferences.getInstance();
runApp(App());
}
Now you can use prefs anywhere without resorting to async code. SharedPreferences will serve as a nonblocking write-through cache, with write operations running asynchronously in the background.
You can call a function on initState() and save SharedPreferences in a variable, so you can use in a non-async method, like this:
SharedPreferences prefs;
Future<void> loadPrefs() async {
prefs = await SharedPreferences.getInstance();
}
#override
void initState(){
super.initState();
loadPrefs();
}

Flutter and Firebase: How can i receive data from function?

i use the following function to fetch userData from Firestore:
Future<String>getRegisterUserData({String userID}) async {
Firestore.instance.collection("Users").document(userID).get().then(
(datasnapshot) {
if (datasnapshot.exists) {
return datasnapshot.data['Email'];
} else {
return "Loading...";
}
},
);
}
I execute this function on my UserProfilePage like this:
_email = widget.firestore.getRegisterUserData(widget.userID).toString();
But i always get the print statement: Instance of 'Future' and not the saved email-address...
i also try this:
Future<String> getRegisterUserData({String userID}) async {
String email;
Firestore.instance.collection("Users").document(userID).get().then(
(datasnapshot) {
if (datasnapshot.exists) {
email = datasnapshot.data['Email'];
} else {
email = "Loading...";
}
},
);
return email;
}
The Print Statement is always the same...
So where is my mistake? I want to display the Value of 'Email' on the UserProfilePage in a variable, or is my firestore function incorrect?
Thank you for our help
Add await keyword. But at a different place.
tempEmail = await widget.firestore.getRegisterUserData(widget.userID);
setState(() {
_email = tempEmail;
});
// we don't need toString as getRegisterUserData itself is returning Future<String>
Note for using await: As we are using await the method/function which contains this should have a async in its signature.
Or you can use then block
widget.firestore.getRegisterUserData(widget.userID).then((email) {
setState(() {
_email = email;
});
});
Explanation: widget.firestore.getRegisterUserData(widget.userID) is of type Future<String>. that's why it is printed as Instance of 'Future'. We have to convert the Future to String by await or by then block
Using SharedPreferences:
Future<String> getEmail() async {
final prefs = await SharedPreferences.getInstance();
String email = prefs.getString('email');
if (email != null) {
return email;
} else {
email = await widget.firestore.getRegisterUserData(widget.userID);
prefs.setString('email', email); //update shared preferences
return email;
}
}
// usage (may be in initState)
widget.getEmail().then((email) {
setState(() {
_email = email;
})
})
Updated
Based on your information, you need a FutureBuilder in order to wait the response to build your widget:
return FutureBuilder(
future: getRegisterUserData(userID: "1234"),
builder: (context, asyncsnapshot){
return asyncsnapshot.hasData && asyncsnapshot.data != null ? TextFormField(
initialValue: asyncsnapshot.data,
) : CircularProgressIndicator();
}
);

Resources