Multi Image Upload causes app to crash saying too many open files - flutter

I am using https://pub.dev/packages/multi_image_picker in my project so that the user can select multiple images.
Following is my code to upload multiple images to Firebase Storage
StorageReference _storageReference = FirebaseStorage.instance
.ref();
await Future.wait(userSelectImages.map((Asset asset) async {
ByteData byteData = await asset.getByteData(quality: 50);
List<int> imageData = byteData.buffer.asUint8List();
StorageUploadTask _uploadTask =
_storageReference.child("$HEALTH_LOG/${asset.name}").putData(imageData);
final StreamSubscription<StorageTaskEvent> _streamSubscription =
_uploadTask.events.listen((event) {
double percent = event != null
? event.snapshot.bytesTransferred /
event.snapshot.totalByteCount
: 0;
});
uploadUrls
.add(await (await _uploadTask.onComplete).ref.getDownloadURL());
await _streamSubscription.cancel();
But I get a crash saying Too many open files and GL_OUT_OF_MEMORY
The code works fine when I select one or two images, but if select 7 to 8 images I get the crash
Edit 2
Alright after debugging more I got to know the real issue. There is no error or bug in the way I am uploading an image to firebase storage. The main issue is to display those user-selected images.
Suppose the user picks multiple images. Now I want to preview those images before the user can upload them to firebase. So I am displaying those images in GridView.Builder which causes the out of memory issue. I have found a bug on Flutter repo regarding this https://github.com/flutter/flutter/issues/21571
So my code for displaying images in GridView is as follows
return GridView.builder(
shrinkWrap: true,
physics: const ScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, childAspectRatio: 1),
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8),
child: AssetThumb(
asset: patientHealthLogsBloc.resultAssetValue[index],
width: MediaQuery.of(context).size.width ~/ 3,
height: 100,
quality: 30,
),
);
},
itemCount: patientHealthLogsBloc?.resultAssetValue?.length ?? 0,
);
If I comment on the above code of displaying previews then images are uploaded properly but displaying those images causes out of memory error. I even tested on the iPad which causes the same issue.

So the real root cause of the issue was that the widget was wrapped in a stream builder which caused it to keep rebuilding it again and again even if data did not changed

Related

Flutter GridView ItemBuilder

I'm building a GridView based on data stored in a Hive box. The data stored in Hive has several objects to it and i need to get to some of that data in order to display it in a GridView.
I have a couple of issues with building the GridView, one i get an issue when first opening the page, where no data is loaded and then i get data after a few seconds, the other issue is that what i've written can't be correct as it just looks too badly written.
This is my code for the GridView builder;
Builder(builder: (context) {
return GridView.builder(
padding: EdgeInsets.zero,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 0,
mainAxisSpacing: 0,
childAspectRatio: 1,
),
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: posList?.length,
itemBuilder:
(context, posIndex) {
PointOfServices? pos = posList
?.elementAt(posIndex);
List<List<Orders>?> ordering = posList!.map((e) => e.orders).toList();
List<Orders>? ordering2 =ordering.elementAt(posIndex);
Orders? ordering3 = ordering2?.elementAt(0);
As you'll see there are several Lists etc to eventually get me to the data i require, it's just not best practice at all, i'm new to Flutter etc :)
This is how i get the data for the posList;
void getPosData() async {
final posData = _orderInfo?.values
.where((posDataMap) =>
posDataMap.deliveryAddressNo == deliveryAddressNo)
.toList();
posDataMap = posData?.asMap();
var posList1 = posDataMap?.values.first.pointOfServices?.toList();
posList = posList1
?.where((element) =>
element.pointOfServiceOrderingGroupNo == posGroupId)
.toList();
}
_orderInfo being my Hive Box data. Data is brought in to the app via an API and stored to my Hive Box.
Do i need to wait for my data to build first before loading the page? Any pointers and feedback would be great.
Thanks

Flutter getx loading data continuously causing UI to be unstable about which data to show

I'm trying to load data from my database using Getx in flutter. I have a list of categories containing a list of sub-categories, and each sub-category has a list of products inside of it. The problem is that the UI of the sub-categories page keeps getting confused which list of data to show, since I'm calling data by category_id. Something that made my app UI unstable and always changing data.
Here is my code for the sub-categories page:
GetBuilder<SubCategoriesController>(builder: (subCategories) {
Get.find<SubCategoriesController>()
.getSubCategories(widget.catId);
print(Get.find<SubCategoriesController>()
.getSubCategories(widget.catId));
return GridView.count(
crossAxisCount: 2,
shrinkWrap: true,
physics: ScrollPhysics(),
mainAxisSpacing: 16,
crossAxisSpacing: 16,
childAspectRatio: 90 / 100,
padding: EdgeInsets.all(16),
children: List.generate(subCategories.subCategoriesList.length,
(index) {
return _buildSingleSubCategory(
index,
SubCategoryModel.fromJson(
subCategories.subCategoriesList[index]));
}),
);
})
I tried to print the output of
Get.find<SubCategoriesController>()
.getSubCategories(widget.catId)
and I figured out that it keeps running continuously without stopping showing: Instance of 'Future<void>'
, and each time it shows data of a specific category, which is pretty weird!
Edit:
Future<void> getSubCategories(int cat_id) async {
Response response = await subCategoriesRepo.getSubCategoriesList(cat_id);
//print(response.body);
if (response.statusCode == 200) {
_subCategoriesList = [];
_subCategoriesList.addAll(response.body);
_isLoaded = true;
update(); // = setState();
}
}
I found out that the update() function called in here is making the issue, but once I remove it I get no data at all.
I think the problem is you are trying to call your getSubCategories(widget.catId) from your builder method.
You can try resolving this issue by calling your getSubCategories(widget.catId) from initstate instead of in builder method like this:
GetBuilder<SubCategoriesController>(
initState: (logic) => logic.getSubCategories(widget.catId),
builder: (subCategories) {
return GridView.count(
crossAxisCount: 2,
shrinkWrap: true,
physics: ScrollPhysics(),
mainAxisSpacing: 16,
crossAxisSpacing: 16,
childAspectRatio: 90 / 100,
padding: EdgeInsets.all(16),
children: List.generate(subCategories.subCategoriesList.length,
(index) {
return _buildSingleSubCategory(
index,
SubCategoryModel.fromJson(
subCategories.subCategoriesList[index]));
}),
);
},
)

How to place network and image picker image in a single grid or listview in flutter

For example on the given image 1 and 2 as a network image in the grid view and others are captured locally.
use gridview.count
GridView.count(
children:[
//widget1() to display NetworkImage
//Widget2() for other NewtorkImage(),
//widget3 to display image captured from imagepicker.
//widget4
])
You can make a list of all images you have and then you can conditionally render the images on the screen. See below example:
List<String> imgUrls = [];
GridView.builder(ctx,index){
gridDelegate:SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 10,
crossAxisSpacing: 4.0,
mainAxisSpacing: 4.0
),
//check if the url is valid
if(isValid) {
NetworkImage(url:imgUrls[index]);
}else if(isValidPath){
//check if the user has uploaded photo to local and path is valid
Image.asset(imgUrls[index]);
}else{
//show error widget
SizedBox();
}
}

Flutter: Display grid of images on PDF

I'm using flutter with the pdf plugin to generate a PDF document where I need to display a grid of images. The images are stored in a List<File>.
Here's what I've tried. Keep in mind that all these widgets are from the pdf package and not from material.
GridView(
crossAxisCount: 5,
childAspectRatio: 1,
children: door.images.map((image) {
return Container(
child: Image(MemoryImage(?????), fit: BoxFit.cover),
);
}).toList(),
),
Note: door.images is the List<File>
How do I convert the File image (from the List<File>) to the Uint8List bytes needed for the MemoryImage widgets?
Convert your File to imagebytes.
final List<int> _imageBytes = await image.readAsBytes();
And then convert the imagebytes to your Uint8List.
final String _uint8List = base64Encode(_imageBytes);

asset images not showing in release version of app in flutter?

I have made a list of images and using ListView.builder to display the images and its working perfectly fine while debugging and even in debug apk of the app but when i use release apk its not showing the images.
List<Activity> act = [
Activity('assets/sports.png', 'Sports', false),
Activity('assets/sleeping.png', 'Sleep', false),
Activity('assets/shop.png', 'Shop', false),
Activity('assets/relax.png', 'Relax', false),]
I am using ListView.builder to show images like this:
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: act.length,
itemBuilder: (context, index) {
return Row(children: <Widget>[
SizedBox(
width: 15,
),
GestureDetector(
child: ActivityIcon(act[index].image)));
Make sure that you've "use-material-design: true" line above assets
There doesn't seem to be an issue from the code you've provided. It'll greatly help if you're able to provide any errors received from the app when the issue occurred. Another way that you can try is by switching to different Flutter channels and see if the app performs better.