Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fastest Way To Display 100 or more images in Flutter

The purpose of this question is to find the best way to display a lot of images (20 or more) from the gallery. I need to display all the photos on the on the device. As you can see there could be a lot of images to be displayed, and when I try to display them all using different Image.file() widget, My phone (LG G2) gets slow and then the app completely crashes.

I think the Problem Is that I am Loading a lot of 4K Images (More Than 100) on a 5 years old Device. The Images actually displayed on the Screen at the same time are actually around 15, but I need to have something like a gallery, so all the images in a GridView.

So, I don't think it's the best option, maybe there is a function to downscale the image to like 100x100 px. But looking online I couldn't find anything. So, Is there a better way?

I get all the Image Paths and their folder using a Platform Channel to Android.

I get them all in a list like this: [["Camera", "storage/emulated/0/downloads/1.png"], etc]

This is The UI I got: (Sorry For the Awful design)

There Are three Main components on the Screen, The IconButton With The Two Arrows: The DropDownMenu and The GridView.

The IconButton requeries all the paths from android. in the List as stated above. The DropDown Menu has a function on onChanged which creates all the Cards in the List used by gridView.

This is The Funciton:

void _onChanged(String value) {
    setState(() {
      _currFolder = value;
      _photoCards = calculatePhotoCards();

    });
  }

And the calculatePhotoCards is this:

List<Widget> calculatePhotoCards() {
    List<Widget> list = new List();

    for (int v = 0; v < _foldersAndPaths.length; v++) {

      if (_foldersAndPaths[v][0] == _currFolder) {


        list.add(Card(
            color: Colors.white,
            shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.all(Radius.circular(20.0))),
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: new ClipRRect(
                borderRadius: new BorderRadius.circular(8.0),
                child: Image.file(
                  File(_foldersAndPaths[v][1]),
                  fit: BoxFit.cover,


              ),
            ),
          ),
        ));
      }
    }

    print(list);
    return list;
  }

Where _foldersAndPaths is the List containing all the paths which their respective folders (as stated above), while _currFolder is the Selected Folder in DropDownMenu.

like image 454
Fabrizio Avatar asked Sep 06 '18 21:09

Fabrizio


3 Answers

You need to add cacheWidth and cacheHeight

example:

Image.network(
  shop.shopPic,
  width: 46,
  height: 46,
  cacheWidth: 46,
  cacheHeight: 46,
)
like image 131
humazed Avatar answered Nov 13 '22 19:11

humazed


I decided to implement this to see if it was something to do with image sizing etc, as there have been a few questions about that in the past for remote images.

When I implemented it, I ran into the exact same problem as you. I thought that flutter did caching of images scaled to a reasonable size but that doesn't seem to be the case. It's actually loading up each image into memory, which is why you're getting a crash. It doesn't take that many images to run out of memory as by the time they're decoded into pixels they're pretty huge.

Here and here are bugs about this (I raised one myself) against flutter.

So unfortunately, I don't think there's a pure flutter way of doing this at the moment. There is a image package on pub that can scale down images but it does it directly in dart code so isn't all that performant.

Until those bugs have been fixed, you may have to look for an android-specific (and iOS-specific if you're interested in that) solution to this. That would entail using the android thumbnail creator to create a bitmap, then either saving that bitmap and passing it's URL back to flutter, or passing the bitmap's bytes directly.

Sorry I don't have a better answer than that!

like image 38
rmtmckenzie Avatar answered Nov 13 '22 17:11

rmtmckenzie


I'm using CachedNetworkImage and I had an issue with loading multiple Images and the app got to over 3GB ram because of it the solution was

CachedNetworkImage(
    height: height,
    width: width,
    memCacheHeight: height, //add this line
    memCacheWidth: width, //add this line
    imageUrl: imageUrl,
  ),

It reduced the memory usage from3GB to 60MB

like image 3
Mohamed Abdallah Avatar answered Nov 13 '22 19:11

Mohamed Abdallah