I am using Firestore as a database and cached_network_image to load and cache images in my flutter app (iOS & Android). I noticed that the app cache size gets too big (+300 mb) after running the app for a while (in debug mode).
Is there a maximum limit on the cache size that app uses in flutter?
Is there a way to force some limit on the cache size such that whenever the cache size reaches its maximum limit, oldest cached files will be removed?
cached_network_image relies on flutter_cache_manager
A CacheManager to download and cache files in the cache directory of
the app. Various settings on how long to keep a file can be changed.
How it works
By default the cached files are stored in the temporary directory of the app. This means the OS can delete the files any time.
Information about the files is stored in a database using sqflite. The file name of the database is the key of the cacheManager, that's why that has to be unique.
This cache information contains the end date till when the file is valid and the eTag to use with the http cache-control.
methods
removeFile removes a file from the cache.
emptyCache removes all files from the cache.
example
void _clearCache() {
DefaultCacheManager().emptyCache();
}
if you want to be able to delete images after sometime you will have to implement a custom cache that deletes images after a given no of days.
from docs TL:DR
class CustomCacheManager extends BaseCacheManager {
static const key = "customCache";
static CustomCacheManager _instance;
factory CustomCacheManager() {
if (_instance == null) {
_instance = new CustomCacheManager._();
}
return _instance;
}
CustomCacheManager._() : super(key,
maxAgeCacheObject: Duration(days: 7),
maxNrOfCacheObjects: 20);
Future<String> getFilePath() async {
var directory = await getTemporaryDirectory();
return p.join(directory.path, key);
}
Image cache can cache up to 1000 images, and up to 100 MB. This may be more but it is min 100 MB.
For your use case use extended_image for caching the image and clear the cache using clearDiskCachedImages method
// Clear the disk cache directory then return if it succeed.
/// <param name="duration">timespan to compute whether file has expired or not</param>
Future<bool> clearDiskCachedImages({Duration duration})
Related
Listview / PageView Widgets do cache data and I don't know where, as well as Image.network and another bunch of widgets do cache data.
I know that you may clear cache by these methods below :-
and the methods mentioned in this thread
How to clear app cache programmatically on Flutter
setState(() {
imageCache.clear();
imageCache.clearLiveImages();
PaintingBinding.instance.imageCache.clear();
});
But I'm not sure that I have deleted ALL cached data allover the app,
Are these enough to clear all cached data or there are more ?
and How can you list and view all the cached data that are misteriously hidden somewhere I don't know where !?
please excuse my ignorance
This would not be the answer as I still don't know how to list and read all the data
but I could gather number of functions that make up a good cocktail to cleanup my heavy app
Future<void> deleteAllCacheThereIsInThisHeavyLaggyAppThatSucksMemoryLikeABlackHole() async {
await Future.wait(<Future>[
getTemporaryDirectory().then((Directory directory) async {
await Directory(directory.path).delete(recursive: true);
}),
getApplicationDocumentsDirectory().then((Directory directory) async {
await Directory(directory.path).delete(recursive: true);
}),
DefaultCacheManager().emptyCache(),
]);
imageCache.clear();
imageCache.clearLiveImages();
PaintingBinding.instance.imageCache.clear();
}
notice that i used this package https://pub.dev/packages/flutter_cache_manager as well
Please feel free to add any method that deletes any hidden magical cached file that I do not know about
I prefer to call these methods multiple times rather than having my app too heavy to navigate
I'm making an Android app, and when using the image picker plugin;
final pickedFile = await ImagePicker().getImage(source: ImageSource.gallery);
File image = File(pickedFile.path);
the 'image' is a copy of the original image in the app's cache, however, I would like to directly use the original image's path to save it in my app because I don't want the apps cache size to grow. I saw that the deprecated method "pickImage" accomplished this (not copying to cache), but the new "getImage" seems to copy automatically and 'image's path is the path of the cached image.
How can I accomplish getting just the original path of the selected image without it being cached? (I'm assuming that using the original file's path would still work to display it in the app with FileImage(File(originalPath)), this is correct assumption?)
On iOS it was never possible to retrieve the original path and on Android it was only possible until SDK 30.
From FAQ of file_picker plugin,
Original paths were possible until file_picker 2.0.0 on Android, however, in iOS they were never possible at all since iOS wants you to make a cached copy and work on it. But, 2.0.0 introduced scoped storage support (Android 10) and with and per Android doc recommendations, files should be accessed in two ways:
Pick files for CRUD operations (read, delete, edit) through files URI and use it directly — this is what you actually want but unfortunately isn’t supported by Flutter as it needs an absolute path to open a File descriptor;
Cache the file temporarily for upload or similar, or just copy into your app’s persistent storage so you can later access it — this is what’s being done currently and even though you may have an additional step moving/copying the file after first picking, makes it safer and reliable to access any allowed file on any Android device.
I have an example for the file_picker package:
var filePath = '';
var fileExtension = '';
var fileName = '';
void buttonOnTap() async {
try {
filePath = await FilePicker.getFilePath(type: FileType.IMAGE);
if (filePath != null) {
fileName = filePath.split('/').last;
fileExtension = fileName.split('.').last;
} else {
filePath = '';
fileName = '';
fileExtension = '';
}
} catch (e) {}
if (filePath != '') {
Image.file(File(filePath), fit: BoxFit.cover);
}
}
I am building an app in flutter and I want to store many images. So will anyone suggest me where I can store the images which is easy to use in my app. I mean should I store it locally or in cloud? If yes which cloud or backend should I use, whichone is good and fully optimized for my flutter app (like mongo, django, firebase etc. ). Will anyone suggest me the best?
Anyone kind of help is appreaciated as I have no prior knowledge about the production part....
Storing Images on a server can be very expensive, since the file sizes are very large compared to the usual data. So if you do not NEED to store them on a server, don't.
Storing images locally is pretty simple. You will want to use the path_provider package https://pub.dev/packages/path_provider . I ll post a function I am using in my current project that does this. You ll see, its pretty simple.
Note: In my Code I pull the file from my server. Obviously leave that part out if you are getting your images from a different source.
Future<File> createFileOfPdfUrl(String fileLocation, String name) async {
final url = Helper.baseUrl + "Files/Newsletter/" + fileLocation;
final filename = url.substring(url.lastIndexOf("/") + 1);
var request = await HttpClient().getUrl(Uri.parse(url));
var response = await request.close();
var bytes = await consolidateHttpClientResponseBytes(response);
String dir = (await pathProvider.getApplicationDocumentsDirectory()).path;
File file = new File('$dir/$filename');
await file.writeAsBytes(bytes);
return file;
}
I try to check if my app has new version. If has new version shows a modal to force to update. I use the firebase remote config package.
The code looks
versionCheck(context) async {
PackageInfo info = await PackageInfo.fromPlatform();
RemoteConfig remoteConfig = await RemoteConfig.instance;
await remoteConfig.fetch();
await remoteConfig.activateFetched();
final currentBuildNumber = int.parse(info.buildNumber);
final requiredBuildNumber = remoteConfig
.getInt('android_app_version');
if (requiredBuildNumber > currentBuildNumber) {
versionDialog(context);
}
}
The problem: currentBuildNumber return the correct number, but the requiredBuildNumber always return '50', so the if conditional doesn´t work as expected. Something is wrong but don't i don't know what. What´s is the rigth way to do this?
If the app fetches so many times in a short period of time it the fetch calls are throttled. Because of the throttling limits, it is not possible for your app to immediately see changes in Remote Config values. Cached values will be used until the next fetch is allowed. The default cache expiration is 12 hours. This is done to optimize the network usage by Remote Config feature.
Keep in mind that this setting should be used for development only,
not for an app running in production. If you're just testing your app
with a small 10-person development team, you are unlikely to hit the
hourly service-side quota limits. But if you pushed your app out to
thousands of test users with a very low minimum fetch interval, your
app would probably hit this quota.
Does anyone know what is maximum size to upload file via Azure HDFS Rest API? (https://learn.microsoft.com/en-us/azure/data-lake-store/data-lake-store-data-operations-rest-api).
I found someplace 256MB, some place 32MB, so wondering.
Or similar limits for other SDKs?
I was wrestling with the same problem some months ago and it turned out that the IIS which is in front of ADLS is setting the maxAllowedContentLength with default value of 30000000 bytes (or 28.6Mb). This essentially means that whenever we want to push anything bigger that 30Mb, that request never reaches ADL as IIS throws 404.13 before that. Reference.
As already suggested in the links, ADLS has a driver with a 4-MB buffer, I'm using the .NET SDK myself and following code has served me well
public async Task AddFile(byte[] content, string path)
{
const int fourMb = 4 * 1024 * 1024;
var buffer = new byte[fourMb];
using (var stream = new MemoryStream(content))
{
if (!_adlsFileSystemClient.FileSystem.PathExists(_account, path))
{
_adlsFileSystemClient.FileSystem.Create(_account, path);
}
int bytesToRead;
while ((bytesToRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
if (bytesToRead < fourMb)
{
Array.Resize(ref buffer, bytesToRead);
}
using (var s = new MemoryStream(buffer))
{
await _adlsFileSystemClient.FileSystem.AppendAsync(_account, path, s);
}
//skipped for brevity
In my tests, I am finding a maximum file size limit somewhere between 28MB and 30MB.
Using the Azure Data Lake Storage REST API, I have had no issues creating files as large as 28MB. However, when I try to create a file that is 30MB, I receive a 404 Not Found error.
The following references align with the file size limit and 404 error I am observing. The references are about the SDK, but it could be that the SDK is also calling the REST API under the covers. My tests are calling the REST API directly.
NotFound error on call to Data Lake Store Create
https://stackoverflow.com/a/41469724/10363