read file returns null Flutter - 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.

Related

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

setState() called after dispose() error after calling async function

I have this button that uploads to Firestore a picture that the user selects and stores the picture url into a varialble to be used to update the user's information.
SELECTION BUTTON calls selectFile().
// SELECTING FILE FOR UPLOAD
Future selectFile() async {
final result = await FilePicker.platform
.pickFiles(allowMultiple: false, type: FileType.image, withData: true);
if (result == null) return;
setState(() {
pickedFile = result.files.first;
texto = Text(pickedFile!.name);
});
}
This successfully changes the state of pickedFiles and Texto variable.
Then I have this other button later in the code that calls uploadFile() and then exits the page with navigator.pop(context).
// UPLOADING FILE AND RETRIEVING DOWNLOAD LINK
Future uploadFile() async {
var fileBytes = pickedFile?.bytes;
var fileName = pickedFile?.name;
var ref = FirebaseStorage.instance.ref().child('UserImages/$fileName');
if (fileBytes == null) {
return '';
}
TaskSnapshot uploadedFile = await ref.putData(fileBytes);
url = await ref.getDownloadURL();
log(url);
if (uploadedFile.state == TaskState.success) {
setState(() { <<<<<<<<--------- setState() called after dispose() ERROR HERE
_petImage = url;
});
}
}
The function does upload the picture to FireStore and even produces a link (tested by using log(url)) but when it reaches the set state it fails.
I have no idea why this is not updating the state of the _petImage variable which stored outside of the main build(context) together with the other variables suck as pickedFile and texto. the setState work fine in other functions but in this function is not working .
what could I be doing wrong here?
It is safe to check if the state is mounted on async and then perform setState.
_() async {
if (mounted) {
setState(() {});
}
}

ReadToken() is returning "Instance of 'Future<Object>'"

ReadToken() is returning "Instance of 'Future'"
I was following this tutorial on the Flutter Docs: https://docs.flutter.dev/cookbook/persistence/reading-writing-files.
So, my problem is that, if I just run ReadToken() without running the create function then the ReadToken() function always returns "Instance of 'Future'". Note: I made some changes to the ReadToken() function, like the name. The function is below.
Future<Object> readToken() 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 0;
}
}
}
Is there anything that I'm doing wrong or anything that I should change?
You have to await readToken(). If you continue reading the documentation by the complete example section, it shows this example:
#override
void initState() {
super.initState();
widget.storage.readCounter().then((value) {
setState(() {
_counter = value;
});
});
}
It's using .then() instead of await, which await is a syntactic sugar for .then()
So, In your case it would be:
readToken().then((value) {
// Do something with the `value`
});

Flutter user data taking up a lot of space

My flutter app user data takes up a lot of space. I'm currently using the following code to save the user data
class FileUtil {
static Future<String> get getFilePath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
static Future<File> get getFile async {
final path = await getFilePath;
return File('$path/user.txt');
}
static Future<File> saveToFile(String data) async {
final file = await getFile;
return file.writeAsString(data);
}
static Future readFromFile() async {
try {
final file = await getFile;
String fileContents = await file.readAsString();
log(fileContents);
return json.decode(fileContents);
} catch (e) {
return "";
}
}
String formatData() {
String formattedString;
Map x = {};
x['a'] = a;
// other variables
formattedString = json.encode(x);
return formattedString;
}
void saveData() async {
try {
await saveToFile(formatData());
//print('DATA SAVED');
} catch (e) {
//print('Could not save data due to: $e');
}
}
}
Whenever the user interacts with something in the app that needs to be saved, I run saveData(). This happens quite often in my app. However, after using the app for a while, the user data can jump to a few hundred MB. I've used a JSON calculator to estimate the space of the formatData() output string and it's much less than 1MB. What should I do to minimise user data?

How to resolve future in dart?

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");