In my app I download the image from URL then save it in local directory. Then next iteration / next app run, the app will just fetch it from local directory.
I download a file from URL like this:
Future<Uint8List> getImageFromCloud(String url) async {
final response = await Client().get(url);
return response.bodyBytes;
}
Then I saved the downloaded bytes into a file like this:
static Future<File> saveFileAsBytes(Uint8List bytes, String path, String filename) async {
// Getting App's local directory
final Directory localRootDirectory = await getApplicationDocumentsDirectory();
final String filePath = p.join(localRootDirectory.path, path, filename);
final file = await File(filePath).create(recursive: true);
final imageFile = await file.writeAsBytes(bytes);
return imageFile;
}
The page state is handled by a bloc like this:
Stream<PageState> initializeBloc(String url) async* {
final bytes = await getImageFromCloud(url);
final imageFile = await saveFileAsBytes(bytes, path, filename);
yield PageReadyState(imageFile);
}
Later in the page's code we use the imageFile for CircleAvatar like this:
Widget onPageReadyState(PageReadyState state) {
// -- Some code
CircleAvatar(
backgroundImage: FileImage(state.imageFile),
);
// -- Some code
}
@override
Widget build(BuildContext context) =>
BlocBuilder<PageBloc, PageState>(builder: (context, state) {
if (state is PageUninitializedState) {
return onPageUninitializedState();
} else if (state is PageReadyState) {
return onPageReadyState(state);
} else return onLoadingPage();
}
But this always crash with Exception: Invalid image data.
This is strange because the bloc has waited for the process of download and writing the file locally to finish before yielding the PageReadyState state.
Then I found out that the file size being returned from getImageFromCloud is not its full size (in one of the case it was 106 while the full file size is 21480). Consequently caused the crash with the CircleAvatar.
Then I run the app the second time and this time I read the same file from local (because it was downloaded on the first run), and the file exist with its full size. This means that the first time it downloads the file, the download was still on going in the background when the function returns the File object to the CircleAvatar, even when I have used the await keyword here. And of course the second time, the file already exist in local directory and thus no crash.
I hope the explanation is clear.
So do you know what am I missing here? Why the await does not wait for the whole file to be done downloading before returning from the function?
Note: tested with different image files with different size, it always return the file with size 106 at first download