How to resolve future in dart? - flutter

I need to read and write files on Flutter.
Write works, but read not or I think it doesn't because the terminal output is flutter: Instance of 'Future<String>'.
What does it means?
This is the code :
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/hello.txt');
}
Future<File> writeHello() async {
final file = await _localFile;
// Write the file.
return file.writeAsString('HelloWorld');
}
Future<String> readHello() async {
try {
final file = await _localFile;
// Read the file.
return await file.readAsString();
} catch (e) {
// If encountering an error, return 0.
return "Can't read";
}
}
.
.
.
writeHello();
print(readHello());

Future<String> is of type Future hence you need to resolve the future, You can either await before printing or use .then() to resolve the Future.
Using await
String data = await readHello();
print(data);
Using .then()
readHello().then((data){ //resolve the future and then print data
print(data);
});
Note: There is no need to add extra "await" here on line 2 as you already are awaiting at line 1:
Future<String> readHello() async {
try {
final file = await _localFile; //Line 1
// Read the file.
return await file.readAsString(); //Line 2
} catch (e) {
// If encountering an error, return 0.
return "Can't read";
}
}

Now I got it, I understood what you said me thank you!
I created a new function that mix write and read.
The problem is that I called async functions in my program body where I can't use await , I should call them in other async functions to handle them in the right way.
I solved with this :
void _RWHello(String text) async {
writeHello();
print(await readHello());
}
.
.
.
_RWHello("HelloWorld");

Related

The await expression can only be used in an async function

I create function in flutter to convert images assets to file and when I call this function with await, the error tell me to add async in the body of my function :
Future<File> getImageFileFromAssets(String path) async {
final byteData = await rootBundle.load('assets/$path');
final file = File('${(await getTemporaryDirectory()).path}/$path');
await file.writeAsBytes(byteData.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
return file;
}
the call :
File ppBase = await getImageFileFromAssets('ppBase.png');
Can you help me please
I don't know what is the problem
You need to convert your method to async to use await
yourMethod() async { //here async
File ppBase = await getImageFileFromAssets('ppBase.png');

Delete file permanantly from list view in flutter

I list all pdf files from storage and now I want to delete multi-files in my flutter list . as well as from the device file manager. I am using this function but when I delete and restart the app the file comes again
This is the function I'm using to delete the list:
void deleteItems() {
var list = myMultiSelectController.selectedIndexes;
list.sort((b, a) => a.compareTo(b));
list.forEach((element) {
files.removeAt(element);
});
setState(() {
myMultiSelectController.set(files.length);
});
}
files.removeAt(element); Just removes file from the list. You need to actually delete file from device.
eg
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
print('path ${path}');
return File('$path/counter.txt');
}
Future<int> deleteFile() async {
try {
final file = await _localFile;
await file.delete();
} catch (e) {
return 0;
}
}
See more here from SO answer

read file returns null Flutter

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.

Why employing getters instead of methods for internal class function in Dart?

I am reading Flutter documentation for Read and write Files, and in this very example I don't really "get" the use of a getter.
(I am new to dart)
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/counter.txt');
}
Future<File> writeCounter(int counter) async {
final file = await _localFile;
// Write the file.
return file.writeAsString('$counter');
}
Are _localPath and _localFile getters or methods ?
Why not write it this way :
Future<String> _localPath() async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> _localFile() async {
final path = await _localPath;
return File('$path/counter.txt');
}
Future<File> writeCounter(int counter) async {
final file = await _localFile();
// Write the file.
return file.writeAsString('$counter');
}
getter is a method that doesn't accept any arguments. And that's why is accessed like any other field and not a method. Basically, it can always be replaced with a method with zero arguments but a getter may be a more elegant way in some cases. For example: your class have a field that holds a date of birth. And you create a getter age instead of a method calculateAge(). You don't really have to, but you can if you prefer

Weird behavior when adding Strings to a list

I am experiencing this weird behavior when loading assets from external storage, sometimes the path gets added to the list and most of the time the path is not added.
Here is my function, Am I missing something?
Future<List<String>> loadAssets() async {
List<String> loadedAssets = [];
loadedAssets.add('test');
try {
final Directory dir = await syspath.getExternalStorageDirectory();
dummyData.forEach((path) async {
final extPath =
path.substring(('assets/products_dummy_data/'.length));
final localPath='${dir.path}/$extPath}';
final file = File(localPath);
if (await file.exists()) {
await file.delete();
}
final data = await rootBundle.load(path);
var asUint8List =
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
await file.create(
recursive: true,
);
await file.writeAsBytes(asUint8List);
if (await file.exists()) {
loadedAssets.add(localPath);
}
});
} catch (e, s) {
AppHelper.appLogger.e('Error while loading assets', e, s);
}
AppHelper.appLogger.i('loadedAssets.length ${loadedAssets.length}');
return loadedAssets;
}
But I always get the length as one, for the test element added
Problem Fixed after using await Future.forEach