In the beginning of system ,I need to load the xml file.
I use async/await to wait for rootBundle.loadString finish.
However in this case, print ("I can wait rootBundle here"); is executed after rootBundle.loadString finish, runApp(MyApp()) starts before finished.
Is there a way to execute runApp() after rootBundle.loadString finish
Because my whole setting is written in one xml files. so I want to make sure to load before first building.
void main(){
inter = new Internationalize();
inter.init();
runApp(MyApp());
}
class Internationalize{
var intls = {};
var xmlBody;
void init(){
print("internationalize class start");
rootBundle.loadString('assets/i18n/en/strings.xml').then(
(String contents) {
var document = xml.parse(contents);
xmlBody = document.findAllElements('string');
print("load finish");
});
print ("I can wait rootBundle here");
}
}
void main() async { // mark it async
WidgetsFlutterBinding.ensureInitialized(); // mandatory since Flutter 1.9 if you're making this method async
inter = new Internationalize();
await inter.init(); // await here
runApp(MyApp());
}
class Internationalize {
var intls = {};
var xmlBody;
Future<void> init() async { // make it Future<void>
print("internationalize class start");
String contents = await rootBundle.loadString('assets/i18n/en/strings.xml'); // await on loadString
var document = xml.parse(contents);
xmlBody = document.findAllElements('string');
print("load finish");
print("I can wait rootBundle here");
}
}
This is the same answer as given by #CopsOnRoad with some explanation.
You should separate the use of future response rootBundle.loadString().
try following:
String contents = await rootBundle.loadString('assets/i18n/en/strings.xml');
var document = xml.parse(contents);
xmlBody = document.findAllElements('string');
print("load finish");
Note: you'll need to add async modifier in all methods, even in the main method as well and add await before every method call.
i.e.:
void main(){
...
await inter.init();
...
}
...
Future<void> init async {
String contents = await rootBundle.loadString('assets/i18n/en/strings.xml');
var document = xml.parse(contents);
xmlBody = document.findAllElements('string');
print("load finish");
}
Related
void main() async {
check();
print('end');
}
Future check() async {
var version = lookUpVersion();
print(version);
}
int lookUpVersion() {
return 12;
}
void main() async {
check();
print('end');
}
Future check() async {
var verion = await lookUpVersion();
print(version);
}
int lookUpVersion() {
return 12;
}
These two code only have one difference, await keyword.
I wonder that why not did they wait for main function code? even I used Future+async keyword at first code.
Can you explain about this?
The async and await keywords provide a declarative way to define asynchronous functions and use their results.
For first one - result will be
//12
//end
For second one - result will be
//end
//12
Which means if you add await it will become asynchronous.
I'm trying to return the exif from the file that I can print directly from within the function, but whenever I use return it sends a Future. Looks like await doesn't work.
import 'dart:io';
import 'package:exif/exif.dart';
consultaDataArquivo(var pathArquivo) async {
final dadosDoArquivo = await pathArquivo.readAsBytesSync();
var dadosExif = await readExifFromBytes(dadosDoArquivo);
return dadosExif;
}
main() {
print(consultaDataArquivo(File('/home/rcaliman/Downloads/_DSC8982.JPG')));
}
because you are not awaiting for the function to return the result.
consultaDataArquivo(var pathArquivo) async {
final dadosDoArquivo = await pathArquivo.readAsBytesSync();
var dadosExif = await readExifFromBytes(dadosDoArquivo);
return dadosExif;
}
main() async{
print(await consultaDataArquivo( File('/home/rcaliman/Downloads/_DSC8982.JPG')));
}
for more officail docs: https://dart.dev/codelabs/async-await
I'm trying to make a package. I need to use async function, but I can't use it while building package.
Package Code:
class Sozluk {
wiki(ceviri) async {
var res = await http.Client()
.get(Uri.parse('https://sozluk.gov.tr/gts?ara=$ceviri'));
var body = res.body;
var decoded = jsonDecode(body);
var json = decoded[0];
var sozlukanlam = json["anlamlarListe"][0]["anlam"];
print(sozlukanlam);
return sozlukanlam;
}
}
Test Code:
void main() {
test('köpek', () {
final sozluk = Sozluk();
var cevap = sozluk.wiki('köpek');
print(cevap);
});
}
The print I got:
Instance of 'Future<dynamic>'
You code is missing a lot of pieces. Just because Dart allows you to write code like a sloppy web developer, does not mean you should. Dart is strongly typed, that is an advantage, please use it.
Problems:
ceviri has no explicit type.
wiki has no explicit return type.
wiki is not awaited
Your anonymous method is not async.
More information about Futures, async and await: What is a Future and how do I use it?
Fixing your code as good as possible:
class Sozluk {
Future<TYPE_X> wiki(TYPE_Y ceviri) async {
var res = await http.Client()
.get(Uri.parse('https://sozluk.gov.tr/gts?ara=$ceviri'));
var body = res.body;
var decoded = jsonDecode(body);
var json = decoded[0];
var sozlukanlam = json["anlamlarListe"][0]["anlam"];
print(sozlukanlam);
return sozlukanlam;
}
}
Test Code:
void main() {
test('köpek', () async {
final sozluk = Sozluk();
var cevap = await sozluk.wiki('köpek');
print(cevap);
});
}
Please note that you need to fill in TYPE_X and TYPE_Y, I have no idea which datatypes best represent your data. Is it a number? A text? You decide.
Yout question is unclear.
If you need to print
sozlukanlam
var in test function you need to await your wiki function becaus it is async.
So you could do somthing like that:
void main() {
test('köpek', () async {
final sozluk = Sozluk();
var cevap = await sozluk.wiki('köpek');
print(cevap);
});
}
OR, if test function couldn't bee async
void main() {
test('köpek', () {
final sozluk = Sozluk();
sozluk.wiki('köpek').then((sozlukanlam)=>print(cevap));
});
}
I have a page that writes a color on file, called "colors.txt".Then the page is closed, when it will be opened again this file will be read and its content (String) printed on the screen.
This is the class that handles reads and writes :
class Pathfinder {
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/colors.txt');
}
Future<File> writeColor(String color) async {
final file = await _localFile;
// Write the file
return file.writeAsString('$color');
}
Future<String> readColor() async {
try {
final file = await _localFile;
// Read the file
final contents = await file.readAsString();
return contents;
} catch (e) {
// If encountering an error, return 0
return "Error while reading colors";
}
}
}
Before page closure, the color has been saved with writeColor, we just need to read the file and print its content.
And this is how I read the color :
void initState() {
super.initState();
String colorRead;
() async {
pf = new Pathfinder();
colorRead = await pf.readColor();
}();
print("Color in initState: " + colorRead.toString());
}
The problem is that colorRead is always null. I already tried .then() and .whenCompleted() but nothing changed.
So my doubt is :
Am I not waiting read operation in right way or the file, for some reasons, is deleted when page is closed?
I think that if file wouldn't exists then readColor should throw an error.
EDIT : How writeColor is called :
Color bannerColor;
//some code
await pf.writeColor(bannerColor.value.toRadixString(16));
void initState() {
super.initState();
String colorRead;
() async {
pf = new Pathfinder();
colorRead = await pf.readColor();
}();
print("Color in initState: " + colorRead.toString()); /// << this will execute before the async code in the function is executed
}
It's null because of how async/await works. The print statement is going to be called before the anonymous async function finishes executing. If you print in inside the function you should see the color if everything else is working correctly.
I currently have an async function that does the following:
Initializes the stream
Call stream.listen() and provide a function to listen to the stream.
await for the stream to get its first result.
The following is some pseudo code of my function:
Future<void> initStream() async {
// initialize stream
var stream = getStream();
// listen
stream.listen((result) {
// do some stuff here
});
// await until first result
await stream.first; // gives warning
}
Unfortunately it seems that calling stream.first counts as listening to the stream, and streams are not allowed to be listened by multiple...listeners?
I tried a different approach by using await Future.doWhile()
Something like the following:
bool gotFirstResult = false;
Future<void> initStream() async {
var stream = getStream();
stream.listen((result) {
// do some stuff here
gotFirstResult = true;
});
await Future.doWhile(() => !gotFirstResult);
}
This didn't work for me, and I still don't know why. Future.doWhile() was successfully called, but then the function provided to stream.listen() was never called in this case.
Is there a way to wait for the first result of a stream?
(I'm sorry if I didn't describe my question well enough. I'll definitely add other details if needed.)
Thanks in advance!
One way is converting your stream to broadcast one:
var stream = getStream().asBroadcastStream();
stream.listen((result) {
// do some stuff here
});
await stream.first;
Another way, without creating new stream, is to use Completer. It allows you to return a Future which you can complete (send value) later. Caller will be able to await this Future as usual.
Simple example:
Future<int> getValueAsync() {
var completer = Completer<int>();
Future.delayed(Duration(seconds: 1))
.then((_) {
completer.complete(42);
});
return completer.future;
}
is equivalent of
Future<int> getValueAsync() async {
await Future.delayed(Duration(seconds: 1));
return 42;
}
In your case:
Future<void> initStream() {
var stream = getStream();
var firstValueReceived = Completer<void>();
stream.listen((val) {
if (!firstValueReceived.isCompleted) {
firstValueReceived.complete();
}
// do some stuff here
});
return firstValueReceived.future;
}