Flutter dart function skipping to end of function after await - dart

I have a function with the keyword async and after the await is done, it skips a bunch of lines of codes and goes to the end of the function after the await is done. Does anyone know what I am doing wrong?
void _createNewGroup(Function createNewGroup, BuildContext context) async {
if (_validateAndSave()) {
try {
print("trying");
Map<String, dynamic> result = await createNewGroup(_group_name);
print("sucess is $result");
if (result['success']) {
print('Success poping dialoge');
Navigator.of(context).pop();
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => HomePage()));
} else {
print("not created group");
}
} catch (error) {}
}
}
Future<Map<String, dynamic>> createNewGroup(String name) async {
var result = {};
var response;
print('Group name $name');
print("creating group");
var group = ParseObject('Groups')
..set("group_name", name)
..set('createdBy_name', _parseUser.get('first_name'))
..set('CreatedBy_id', _parseUser.objectId)
..set('members', [{'name': _parseUser.get('first_name'), 'id': _parseUser.objectId}]);
response = await group.save();
if(response.success) {
print('sucess creating object');
result = {'success': true, 'message': 'New Group Created'};
return result;
} else {
result = {'success': false, 'message': 'Error occured creating group'};
}
print("result is $result");
print("response is ${response.result}");
return result;
}

Related

Why can't catch exceptions with "catchError" in Dart?

Test:
void testAs() async {
try {
String b = await test();
print(b);
} catch (e) {
print("1 await error");
}
test().then((value) => print(value)).catchError(() {
print("2 then error");
});
}
Future<String> test() {
List<String> bb = ["2222"];
return Future.value(bb[1]);
}
1 await error
RangeError (index): Invalid value: Only valid value is 0: 1
Why is it ineffective?
If I want to deal with "future" through "then", how should I catch the exception and not let it throw out.
Thank you friends,the last problem has been solved,the problem can be solved by adding async and await flags to the test() method.
But there is a new problem, Now I use the correct code and find that it can only be printed once.why can't it print "then success",then the program ends
,modify as follows:
void testAs() async {
try {
await test();
print("await success");
} catch (e) {
print("await error");
}
test().then((value) => print("then success")).catchError((e) {
print("then error");
});
}
Future<String> test() async{
List<String> bb = ["2222"];
return await Future.value(bb[0]);
}
print:await success

After web request, navigate to other view (async /await proper usage) - Flutter , dart

I want to fetch data from the server, then parse json. When they are done, I want to navigate to another view.
void getServerData() async{
WebRequests ws = WebRequests('https://sampleurl');
Map<String, dynamic> map = await ws.getData();
mychamplist = map['mychampionships'];
mychamplist.forEach((f){
mychampionships.add(MyChampionships(
name: f['name'],
id: int.parse(f['id']),
numberOfPlayers: int.parse(f['nofplayers']),
));
});
Navigator
.of(context)
.pushReplacement(new MaterialPageRoute(builder: (BuildContext context) {
return FantasyNbi();
}));
}
It navigates to the FantasyNbi class before the previous code finished.
How could it do in proper way?
I do have a example class for you that you could use:
class API {
static Future getData(String url) {
return http.get('api link' + url);
}
static Future<List<BasicDiskInfo>> fetchAllDisks() async {
final response = await getData('disk');
if (response.statusCode == 200) {
Iterable list = json.decode(response.body);
List<BasicDiskInfo> disks =
list.map((model) => BasicDiskInfo.fromJson(model)).toList();
return disks;
} else {
throw Exception('Failed to load disks');
}
}
static Future<Disk> fetchDisk(int id) async {
final response = await getData('disk/' + id.toString());
if (response.statusCode == 200) {
return Disk.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load disk');
}
}
}
class Disk {
int id;
String name;
String volumeLable;
bool isReady;
String driveType;
String driveFormat;
int totalSize;
int totalFreeSpace;
int availableFreeSpace;
Disk(
{this.id,
this.name,
this.volumeLable,
this.isReady,
this.driveType,
this.driveFormat,
this.totalSize,
this.totalFreeSpace,
this.availableFreeSpace});
factory Disk.fromJson(Map<String, dynamic> json) {
return Disk(
id: json['id'],
name: json['name'],
volumeLable: json['volumeLable'],
isReady: json['isReady'],
driveType: json['driveType'],
driveFormat: json['driveFormat'],
totalSize: json['totalSize'],
totalFreeSpace: json['totalFreeSpace'],
availableFreeSpace: json['availableFreeSpace']);
}
}
And to get the data I can do this:
var data = await API.fetchAllDisks();
// or
API.fetchAllDisks().then((response) => {/* do something */})

Flutter get logged user data to other screen view

I have API.dart like this to authenticating a user, log in and log out
class Api {
static FirebaseAuth _auth = FirebaseAuth.instance;
static GoogleSignIn _googleSignIn = GoogleSignIn();
FirebaseUser firebaseUser;
Api(FirebaseUser user) {
this.firebaseUser = user;
}
static Future<FBApi> signInWithGoogle() async {
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
final FirebaseUser user = await _auth.signInWithGoogle(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
assert(user.email != null);
assert(user.displayName != null);
assert(await user.getIdToken() != null);
final FirebaseUser currentUser = await _auth.currentUser();
assert(user.uid == currentUser.uid);
// print('photoURL api ' + user.photoUrl);
return Api(user);
}
static Future<void> signOut() async {
await _auth.signOut().then((_) {
print("***** log out...what the hell?");
_googleSignIn.signOut();
});
}
}
I've have a cloud function to create new user to database cloud firestore.
And in view account settings, I want to update user information like displayName, photoUrl into firestore. How I get current user in my account setting view.
class Settings extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(
'ACCOUNT',
style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold),
),
centerTitle: true,
),
body: new SettingsScreen(),
);
}
}
class SettingsScreen extends StatefulWidget {
#override
State createState() => new SettingsScreenState();
}
class SettingsScreenState extends State<SettingsScreen> {
TextEditingController controllerNickname;
SharedPreferences prefs;
String id;
String nickName;
String photoUrl;
bool isLoading = false;
File avatarImageFile;
final FocusNode focusNodeNickname = new FocusNode();
#override
void initState() {
super.initState();
readLocal();
}
void readLocal() async {
prefs = await SharedPreferences.getInstance();
id = prefs.getString('id') ?? '';
nickName = prefs.getString('nickName') ?? '';
photoUrl = prefs.getString('photoUrl') ?? '';
controllerNickname = new TextEditingController(text: nickName);
// Force refresh input
setState(() {});
}
Future getImage() async {
File image = await ImagePicker.pickImage(source: ImageSource.gallery);
if (image != null) {
setState(() {
avatarImageFile = image;
isLoading = true;
});
}
uploadFile();
}
Future uploadFile() async {
String fileName = id;
StorageReference reference = FirebaseStorage.instance.ref().child(fileName);
StorageUploadTask uploadTask = reference.putFile(avatarImageFile);
StorageTaskSnapshot storageTaskSnapshot;
uploadTask.onComplete.then((value) {
if (value.error == null) {
storageTaskSnapshot = value;
storageTaskSnapshot.ref.getDownloadURL().then((downloadUrl) {
photoUrl = downloadUrl;
Firestore.instance
.collection('users')
.document(id)
.updateData({'displayName': nickName, 'photoUrl': photoUrl}).then((data) async {
await prefs.setString('photoUrl', photoUrl);
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: "Upload success");
}).catchError((err) {
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: err.toString());
});
}, onError: (err) {
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: 'This file is not an image');
});
} else {
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: 'This file is not an image');
}
}, onError: (err) {
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: err.toString());
});
}
void handleUpdateData() {
focusNodeNickname.unfocus();
setState(() {
isLoading = true;
});
Firestore.instance
.collection('users')
.document(id)
.updateData({'displayName': nickName, 'photoUrl': photoUrl}).then((data) async {
await prefs.setString('nickname', nickName);
await prefs.setString('photoUrl', photoUrl);
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: "Update success");
}).catchError((err) {
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: err.toString());
});
}
#override
Widget build(BuildContext context) {
...
You can do something like this FirebaseAuth.instance.currentUser()
This returns the current user if any. Otherwise it returns null

future functions keep repeating

am trying to read and write in files in my flutter app .. like this:
Future<String> get _localPath async {
print('hi');
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
File f = File('$path/mypollshash.txt');
if (f.existsSync()) {
print('exists');
String contents = await f.readAsString();
content = contents;
fetchHash();
} else {
print('not exists');
fetch();
}
return f;
}
Future checkfileexist() async {
try {
final file = await _localFile;
String contents = await file.readAsString();
content = contents;
} catch (e) {
//return 'nothing';
}
}
Future<File> writehash(String hash) async {
final file = await _localFile;
return file.writeAsString('$hash', mode: FileMode.write);
}
Future<File> get _localjson async {
final path = await _localPath;
return File('$path/mypolls.json');
}
Future<File> writejson(String json) async {
final file = await _localjson;
return file.writeAsString('$json', mode: FileMode.write);
}
readjson() async {
try {
final file = await _localjson;
String contents = await file.readAsString();
content = contents;
setState(() {
polls = pollsFromJson(content);
isloading = false;
});
writejson(pollsToJson(polls));
writehash(polls.hash);
print('here');
// return contents;
} catch (e) {
fetch();
print('there');
print(e);
// If we encounter an error, return 0
//return 'nothing';
}
}
fetch() async {
String data =
await DefaultAssetBundle.of(context).loadString("assets/mypolls.json");
setState(() {
polls = pollsFromJson(data);
isloading = false;
});
writejson(pollsToJson(polls));
writehash(polls.hash);
}
fetchHash() async {
String data = await DefaultAssetBundle.of(context)
.loadString("assets/pollshash.json");
print(content);
final pollshash = pollshashFromJson(data);
if (content == pollshash.hash) {
print('take from the saved json');
readjson();
} else {
print('call api');
fetch();
}
}
and then am calling it here:
#override
void initState() {
super.initState();
checkfileexist();
}
this works fine .. but the method will keep called even when i go to another page and will get this printed over and over again:
I/flutter (17060): hi
I/flutter (17060): here
I/flutter (17060): exists
I/flutter (17060): d1f4bd60f52991d100adafa416f48b52
I/flutter (17060): take from the saved json
I want this to be called only once .. how to do this?
InitState is not called once it's normal. Instead you can do it with multiple solutions.
Create an attributes in your component to memorize if you already did your checks like this
class MyComponentState ... {
bool hasChecked = false;
bool isFileExists = false;
#override
initState() {
super.initState();
if(!hasChecked) {
this.hasChecked = true;
this.isFileExists = checkfileexist();
}
}
}

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