Evict image from cache flutter not working - flutter

I'm trying to remove a single image entry from the flutter cache using the evict() method from the NetworkImage class and it keeps failing.
Here how I do the evict:
final NetworkImage provider = NetworkImage(url);
try {
bool res = await provider.evict();
print("eviction result : $res");
} catch (error) {
print(error.toString());
}
And how my image is rendered:
CircleAvatar(
radius: 80,
backgroundImage: NetworkImage(url))),
This print flutter: eviction result : false in the console and the image cache is not removed. Any idea of what i'm missing ?

Related

Flutter Exception Won't Catch Invalid Image Data

I have a synchronous method that reads an image from disk. I'm trying to handle all scenarios where the image didn't get saved properly and is corrupted.
If I place a fake.jpg in my app's documents folder and then run the below code on it, it crashes with: Invalid image data. So the Image.file portion of my code isn't catching an underlying exception.
Widget getPhotoFile(String path) {
final file = File(path);
try {
if (!file.existsSync()) throw Exception('Photo Not Available');
final photo = Image.file(
key: UniqueKey(),
file,
fit: BoxFit.cover,
);
return photo;
} catch (error) {
return Text('No Image');
}
}
Why won't my catch block work for the Image exception and return the Text widget instead?

Upload race condition - Google Firebase Storage

I am attempted to update an avatar on my app and then load and display it once done. However, I am seeing the following errors which seem to indicate a false positive or race condition when the image has actually finished uploading.
I'm using a CicleAvatar widget, but also attempted with NetworkImage and am experiencing the same issues. I have also attempted .then/onComplete and various others outside of a delayed or wrapping it in a completer.
What is the best way to handle Firebase storage upload and immediate download without error§
Example Error n attempting to retrieve the image from the DownloadURLL:
════════ Exception caught by image resource service
════════════════════════════ HTTP request failed, statusCode: 503,
!isImageProcessing
? GestureDetector(
onTap: () => _uploadAvatarImage(),
child: CircleAvatar(
minRadius: 40,
backgroundColor: Colors.grey,
backgroundImage: NetworkImage(user.imageURL),
),
)
: Center(
child: CircularProgressIndicator(),
),
The actual upload of the file is being managed in this function/class
class StorageController {
static Future<String> storeAvatarImage(File file) async {
// Get user UUID to reference avatar;
String uuid = await identityBloc.retrieveActiveUUID();
String downloadURL;
TaskSnapshot ts;
ts = await firebase_storage.FirebaseStorage.instance
.ref('avatars/$uuid-avatar.png')
.putFile(file);
downloadURL = await ts.ref.getDownloadURL();
User user = await ProfileDataController.retrieveUserProfile();
user.imageURL = downloadURL;
await ProfileDataController.createUserProfile(user);
downloadURL = downloadURL;
return downloadURL;
}
}
I think you are not properly awaiting for the file upload. Can you change this line to read:
ts = await firebase_storage.FirebaseStorage.instance
.ref('avatars/$uuid-avatar.png')
.putFile(file);
// removed the below part
// .snapshot;
The image would update if there are listeners to listen to changes in the changed user avatar.
What I would advise as a workaround is store the avatarUrl to firestore or rtdb, there you can set a listener that updates the UI on the frontend when a change is written there.
Initially, the avatarUrl field would be null then when a user uploads a new picture the field is then a string and you can supply it to your UI

File is not loading from DocumentDirectory Path Flutter

i am new to Flutter.
I build simple demo app in which user can fill simple form and once user press button then those data will save into SQLite DB.
There's only 3 content. Title, Image Path (Image saved to DocumentDirectory), Location Details.
Add Screen
Listing Screen
Below is my code to copy image to path.
Future<void> _takePicture() async {
final picker = ImagePicker();
final pickedFile = await picker.getImage(
source: ImageSource.camera,
maxWidth: 600,
);
if (pickedFile == null) {
return;
}
setState(() {
_storedImage = File(pickedFile.path);
});
final appDir = await syspaths.getApplicationDocumentsDirectory();
String relativePath = '/' +
DateTime.now().millisecondsSinceEpoch.toString() +
path.basename(pickedFile.path);
String newPath = '${appDir.path}' + relativePath;
final savedImage = await File(pickedFile.path).copy('$newPath');
widget.onSelectImage(savedImage);
}
Listing Item Code
child: Card(
elevation: 5,
child: ListTile(
leading: CircleAvatar(
backgroundImage: FileImage(greatPlaces.items[index].image),
),
title: Text(greatPlaces.items[index].title),
subtitle: Text(
greatPlaces.items[index].location.address),
onTap: () {
print(greatPlaces.items[index].image);
//Go to detail page...
},
),
)
ISSUE ==> When i add new place and view the added place list then images are loading fine but when i stop and rerun project then i am getting below error and image is not loading.
ERROR
════════ Exception caught by image resource service
════════════════════════════ The following FileSystemException was
thrown resolving an image codec: Cannot open file, path =
'/var/mobile/Containers/Data/Application/607FB621-ABDA-472F-8B7A-D9B1BEC4A15D/Documents/1616508266743image_picker_34814E6F-218C-48F6-BE36-C4D7949F0496-1511-0000017478AD7F14.jpg'
(OS Error: No such file or directory, errno = 2) When the exception
was thrown, this was the stack
#0 _File.open. (dart:io/file_impl.dart:356:9) (elided 13 frames from dart:async) Path:
/var/mobile/Containers/Data/Application/607FB621-ABDA-472F-8B7A-D9B1BEC4A15D/Documents/1616508266743image_picker_34814E6F-218C-48F6-BE36-C4D7949F0496-1511-0000017478AD7F14.jpg ════════════════════════════════════════════════════════════════════════════════
I downloaded app container and confirm image exist at the same place. greatPlaces.items[index].image return the File
NOTE: ==> Same code working fine in Android Devices.
it will be very helpful if someone help me with this. Thanks
Path of the documents directory changes on iOS after each app update. Therefore, one can not store absolute paths to the files stored in this directory. Instead, it is required to store the relative paths and then join them with the value returned by getApplicationDocumentsDirectory() every time to access the files.

What is the proper way to load images in Flutter and handle exceptions on load

I'd like to know what is the proper way to load images from the device, and handle exceptions if the image is missing or corrupted. The user picking an image from the device and I want to open it. I'm using the image later in my code, so it is not enough for me just to show it in some widget.
Currently, I'm using the following code that works fine in most cases:
Future<ui.Image> imageLoadFromDevice(String path) async {
await askPermissionForStorage();
ImageProvider imageProvider = FileImage ( File ( path ), scale: 1 );
Completer<ImageInfo> completer = Completer();
imageProvider.resolve(ImageConfiguration()).addListener(ImageStreamListener((ImageInfo info, bool _) {
completer.complete(info);
}));
ImageInfo imageInfo = await completer.future;
return imageInfo.image;
}
But if the image is missing or corrupted, there is a print in the console "Exception caught by image resource service", but my exception catcher above this function not getting the exception.
Do I loading the image properly, or is there a better way?
In case this code is OK, how should I catch exceptions, particularly missing file or corrupted image?
I'm not sure about corrupted images, but in the case of missing files, you can store the File(path) in a variable and use varname.exists() to check before setting your ImageProvider.
Good question! :)
You can use a simpler code below, that loading an image just as you want.
import 'dart:ui' as ui;
Future<ui.Image> imageLoadFromDevice(String path) async {
await askPermissionForStorage();
File fileImage = File(path);
final Uint8List imageUint8List = await fileImage.readAsBytes();
final ui.Codec codec = await ui.instantiateImageCodec(imageUint8List);
final ui.FrameInfo frameInfo = await codec.getNextFrame();
return frameInfo.image;
}
To catch exceptions from this code you can put it inside try-catch. Any exception while loading the image, should produce a general exception that can be caught and handled.
To handle errors from an ImageStream, use the onError argument to the ImageStreamListener constructor:
imageProvider.resolve(ImageConfiguration()).addListener(ImageStreamListener(
(ImageInfo info, bool _) { }, // called for success
onError: (Object error, StackTrace? stackTrace) { }, // called for error
));

Flutter remove image after upload using image_picker package

I have managed to upload an image using the image picker package as shown below:
final picker = ImagePicker();
Future selectPhoto() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
_image = File(pickedFile.path);
});
}
The image has been displayed on the device where I have a remove button which I can use to remove the image and upload another before saving it.
child: Container(
height: height * 0.2,
width: width * 0.2,
child: Image.file(
_image,
fit: BoxFit.fill,
),
),
My question is how can I remove the image from cache as this piece is not working
onTap: () {
setState(() {
imageCache.clear();
print('removes $_image');
});
},
You have a misunderstanding of what the cache is compared to explicitly storing a file in memory with your code. Flutter may store images that you use in widgets in a cache so that they may load faster in the future. imageCache.clear(); does clear the cache and is likely doing it's work in your code. However, your method of checking if the image is still cached is flawed.
imageCache.clear(); only clears the cache, it does not delete the file that you're passing to the Image.file widget. This means that _image(the file variable you have stored in memory) will persist even over the cache clearing. To truly delete this image you could use the delete method or if you just want to stop showing the image, deference the file by setting the file reference to null:
_image = null;
Solved it by calling a method within the button which had set state method where the path was returned back to null
clearimage() {
setState(() {
_image = null;
});
}