Load phone's gallery as fast as native IOS in Flutter without OOM
You can use a logic like this :
final Map<String, Uint8List?> _cachedMap = {};
void precacheAssets(int index) async {
// Handle cache before index
for (int i = max(0, index - 50); i < 50; i++) {
getItemAtIndex(i);
}
// Handle cache after index
for (int i = min(assetsList.length, index + 50); i < 50 + min(assetsList.length, index + 50); i++) {
getItemAtIndex(i);
}
_cachedMap.removeWhere((key, value) {
int currIndex = assetsList.indexWhere((element) => element.id == key);
return currIndex < index - 50 && currIndex > index + 50;
});
}
/// Get the asset from memory or fetch it if it doesn’t exist yet.
/// Called in the builder method to display assets, not to precache them.
Future<Uint8List?> getItemAtIndex(int index) async {
AssetEntity entity = assetsList[index];
if (_cachedMap.containsKey(entity.id)) {
return _cachedMap[entity.id];
}
else {
Uint8List? thumb = await entity.thumbDataWithOption(
ThumbOption.ios(
width: width,
height: height,
deliveryMode: DeliveryMode.highQualityFormat,
quality: 90));
_cachedMap[entity.id] = thumb;
return thumb;
}
}
And you can call the precacheAssets
method in your GridView.builder
at a specific index for example if (index % 25 == 0)
which will tell every 25 items, put in cache the 50 next ones so it will add 25 more items to the existing cache.
Also, call the getItemAtIndex
in your Future.builder
as future
param and you will get instantly the asset if it’s in memory, otherwise load it as usual.
Feel free to change the values and test it, it’s already improved with these values in my iPhone but if you are scrolling VERY fast you will still see as before a bit.
You can add a FadeTransition
in this case which will result in a non-ugly UI.
Tom3652
Updated on January 01, 2023Comments
-
Tom3652 over 1 year
I am trying to load the phone's gallery (with pagination) in a
GridView.builder
widget.Here is the issue i have created using the
photo_manager
package.
I have got some help and it made me think about a possible solution (see my last comment on the issue).I would like to be able to load the assets without blinking or white page.
On IOS native it's veeery fast and smooth, i want to achieve the same in Flutter.You will find all the pieces of code i have made in the github link above. I have managed to do so using a
Map
object in memory but i need to improve the algorithm to not be in OOM.Solutions wanted (one or the other) :
- A simple way to do this, load the phone's gallery as fast as the native IOS into a
GridView
, no matter which package is used the time it's working. - An improvement of my currently poor algorithm that would keep for example the 15 assets above the current one, 15 assets below in memory and during the scroll, keep updating these values to move the range around the current position in the list.
Please let me know if this is not clear enough, as a reminder please have a look at my last big comment on this issue.
-
Tom3652 over 2 yearsBefore asking to close because it "needs more focus", please specify in the comment what is not clear and i will update the question. The use case is very simple, i just need the phone's gallery to be loaded as fast as the IOS native gallery.
-
Omatt over 2 yearsIf you just need to create an image gallery as an image picker, have you considered using image_picker plugin?
-
Tom3652 over 2 yearsI need to customize the Gallery. This means i have to build a custom UI page that will load the items + other UI specifications.
image_picker
works well but it opens a newIntent
/ new page that is not customizable. If i am wrong, please feel free to write an answer.
- A simple way to do this, load the phone's gallery as fast as the native IOS into a
-
Tom3652 over 2 yearsThanks for taking time to reply. However it doesn't work as expected. Have you checked my github issue ? I am already using thumbnails even 64x64 to test and it doesn't work. I have actually also provided a begining of solution on the Github. With yours, i am seeing the same as i have requested on Github :( I have checked your code, and you are using the same methods as i am and items take too much time to be loaded in the
GridView
unfortunately :/. What i need is a fluent user experience without empty screens for fewmilliseconds
when scrolling very fast. -
Andrey Gordeev over 2 yearsThen you need to precache thumbnails in the background after the page is opened, using
album.getAssetListRange
-
Tom3652 over 2 yearsYou are right and that's what i have started to do, this question is about an implementation of this solution actually, working with 5k + assets and precaching only 20-30 maximum ahead (scrolling up + down) to minimize memory load and avoid OOM.
-
Tom3652 over 2 yearsThanks for your answer. Since it still doesn't load as fast as native IOS perfectly, i don't set it as an accepted answer yet in case someone finds a better way, but i am tuning a bit your example and i have something really satisfying !