Infinite scroll loading Pagination problem in ListView Flutter - flutter

Problem with displaying images in ListView, have error app crash when load all images at once and pagination code i have now is not work for some reason
Basicly want to fetch images from this firebase colection and display them in 'ListView' with pagination to my app not crash.
Hopfuly somebody can help me fix this issue, thank you!
initSliderImages() async {
var result = await FirebaseFirestore.instance.collection('galerytab1');
result.snapshots().listen((data) {
List imgs = [];
data.docChanges.forEach((change) {
var imageData = change.doc.data();
String image = imageData?['url'];
imgs.add(CachedNetworkImage(imageUrl: image));
});
setState(() {
images = imgs;
});
});
}
class _CategoryTab1State extends State<CategoryTab1> {
List images = [];
late ScrollController controller;
final scaffoldKey = GlobalKey<ScaffoldState>();
#override
void initState() {
super.initState();
// addUrls();
controller = ScrollController()..addListener(_scrollListener);
initSliderImages();
if (this.mounted) {
context.read<CategoryTab1Bloc>().data.isNotEmpty
? print('data already loaded')
: context.read<CategoryTab1Bloc>().getData(mounted, widget.category);
}
}
#override
void dispose() {
controller.removeListener(_scrollListener);
super.dispose();
}
void _scrollListener() {
print(controller.position.extentAfter);
if (controller.position.extentAfter < 2) {
setState(() {
print('add 2 more');
print('add 2 more');
print('add 2 more');
print('add 2 more');
// images.addAll(['item1','item2','item3']
// List.generate(2, (index) => 'Inserted $index'
// )
// );
});
}
}
// //
// void addUrls() {
// final List<String> imgs = List.generate(
// 16,
// (_) {
// int random = Random().nextInt(16) + 16; // 250-500
// return
// // initSliderImages();
// // 'https://picsum.photos/$random/$random';
// 'https://firebasestorage.googleapis.com/v0/b/klosterkatz-c914e.appspot.com/o/galerytab1%2F1.png?alt=media&token=5b0e9c74-ec5a-42ca-aa59-309f41938a28';
//
//
//
//
// },
// );
// setState(() {
// images.addAll(imgs);
// });
// }
//
// Fetch images from databse for list
initSliderImages() async {
final int _limit = 3;
var result = await FirebaseFirestore.instance.collection('galerytab1');
result.snapshots().listen((data) {
List imgs = [];
data.docChanges.forEach((change) {
var imageData = change.doc.data();
String image = imageData?['url'];
imgs.add(image);
});
setState(() {
images = imgs;
});
});
}
#override
Widget build(BuildContext context) {
print('imagesimageimagesimagesimageismageimage');
print('$images');
print(images.length);
return NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
if (notification.metrics.pixels ==
notification.metrics.maxScrollExtent) {
initSliderImages();
_scrollListener();
// addUrls();
}
return true;
},
child:
ListView.builder(
controller: controller,
key: widget.key,
itemCount: images.length,
itemExtent: 250,
itemBuilder: (context, index) {
return CachedNetworkImage(
imageUrl: images[index],
fit: BoxFit.cover,
key: ValueKey(images[index]),
);
}
),
);
}
}

In listview.Builder add shrinkWrap : primary false if not true

App is crashing due to memory issue. Following code is for proper pagination using firestore. Hope it will help you.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
class CategoryTab1 extends StatefulWidget {
const CategoryTab1({Key? key}) : super(key: key);
#override
State<CategoryTab1> createState() => _CategoryTab1State();
}
class _CategoryTab1State extends State<CategoryTab1> {
final _controller = ScrollController();
var _images = <String>[];
/// Flag for first time loading
var _isLoading = true;
/// Flag for paginated loading
var _isSubLoading = false;
/// last snapshot reference for pagination
QueryDocumentSnapshot<Map<String, dynamic>>? _lastSnapshot;
/// length of last images fetched
var _length = 10;
/// can load more if length is equal or more than 10
/// if less than 10 it means all images have been fetched
bool get _canLoadMore => _length >= 10;
#override
void initState() {
super.initState();
_loadData();
_controller.addListener(_listener);
}
#override
void dispose() {
_controller.removeListener(_listener);
_controller.dispose();
super.dispose();
}
void _listener() {
if (!_canLoadMore) {
return;
}
if (_isSubLoading || _isLoading) {
return;
}
if (_controller.position.extentAfter <= 0) {
_loadData();
}
}
final _collection = FirebaseFirestore.instance.collection('galerytab1');
void _loadData() async {
try {
if (_lastSnapshot != null) {
_isSubLoading = true;
setState(() {});
}
late QuerySnapshot<Map<String, dynamic>> _result;
/// Fetching images
if (_lastSnapshot == null) {
/// First time loading
_result = await _collection.limit(10).get();
} else {
/// Paginated loading
_result = await _collection
.startAfterDocument(_lastSnapshot!)
.limit(10)
.get();
}
final docs = _result.docs;
_length = docs.length;
for (final doc in docs) {
String im = doc.data()['url'] ?? '';
if (im.isNotEmpty) _images.add(im);
}
if (docs.isNotEmpty) _lastSnapshot = docs.last;
} catch (_) {}
_isLoading = false;
_isSubLoading = false;
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: ListView.builder(
controller: _controller,
itemCount: _images.length,
addAutomaticKeepAlives: true,
itemBuilder: (context, index) {
return CachedNetworkImage(
imageUrl: _images[index],
fit: BoxFit.cover,
key: ValueKey(_images[index]),
);
},
),
),
if (_isSubLoading) CircularProgressIndicator(),
],
),
);
}
}

Related

Problem display images in ListView with infinity pagination

Problem with displaying images in ListView, have error that 'CachedNetworkImage' is nota subtype of type 'String'
Basicly want to fetch images from this firebase colection and display them in 'ListView' with pagination
initSliderImages() async {
var result = await FirebaseFirestore.instance.collection('galerytab1');
result.snapshots().listen((data) {
List imgs = [];
data.docChanges.forEach((change) {
var imageData = change.doc.data();
String image = imageData?['url'];
imgs.add(CachedNetworkImage(imageUrl: image));
});
setState(() {
images = imgs;
});
});
}
class CategoryTab1 extends StatefulWidget {
final String category;
CategoryTab1({Key? key, required this.category}) : super(key: key);
#override
_CategoryTab1State createState() => _CategoryTab1State();
}
class _CategoryTab1State extends State<CategoryTab1> {
List images = [];
late ScrollController controller;
final scaffoldKey = GlobalKey<ScaffoldState>();
#override
void initState() {
super.initState();
// addUrls();
controller = ScrollController()..addListener(_scrollListener);
initSliderImages();
if (this.mounted) {
context.read<CategoryTab1Bloc>().data.isNotEmpty
? print('data already loaded')
: context.read<CategoryTab1Bloc>().getData(mounted, widget.category);
}
}
#override
void dispose() {
controller.removeListener(_scrollListener);
super.dispose();
}
void _scrollListener() {
print(controller.position.extentAfter);
if (controller.position.extentAfter < 13) {
setState(() {
images.addAll(List.generate(2, (index) => 'Inserted $index'));
});
}
}
// //
// void addUrls() {
// final List<String> imgs = List.generate(
// 16,
// (_) {
// int random = Random().nextInt(16) + 16; // 250-500
// return
// // initSliderImages();
// // 'https://picsum.photos/$random/$random';
// 'https://firebasestorage.googleapis.com/v0/b/klosterkatz-c914e.appspot.com/o/galerytab1%2F1.png?alt=media&token=5b0e9c74-ec5a-42ca-aa59-309f41938a28';
//
//
//
//
// },
// );
// setState(() {
// images.addAll(imgs);
// });
// }
//
// Fetch images from databse for list
initSliderImages() async {
var result = await FirebaseFirestore.instance.collection('galerytab1');
result.snapshots().listen((data) {
List imgs = [];
data.docChanges.forEach((change) {
var imageData = change.doc.data();
String image = imageData?['url'];
imgs.add(CachedNetworkImage(imageUrl: image));
});
setState(() {
images = imgs;
});
});
}
#override
Widget build(BuildContext context) {
print('imagesimageimagesimagesimageismageimage');
print('$images');
print(images.length);
return NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
if (notification.metrics.pixels ==
notification.metrics.maxScrollExtent) {
initSliderImages();
// addUrls();
}
return true;
},
child: ListView.builder(
key: widget.key,
itemCount: images.length,
itemExtent: 250,
itemBuilder: (context, index) {
return Image.network(
images[index],
fit: BoxFit.cover,
key: ValueKey(images[index]),
);
},
),
);
}
}
You can't add CachedNetworkImage in a list of String !
You have to map each url of your images list into a CachedNetworkImage like this :
itemBuilder: (context, index) {
return CachedNetworkImage(
imageUrl: images[index],
fit: BoxFit.cover,
key: ValueKey(images[index]),
);
}
You should also rename your images variable into urls or imageUrls

Flutter List View Pagination lazy load the images from firebase

i try to implement pagination on my image list from firebase, and i need some help..
// Fetch images from databse for list
initSliderImages() async {
var result = await FirebaseFirestore.instance.collection('galerytab1');
result.snapshots().listen((data) {
List imgs = [];
data.docChanges.forEach((change) {
var imageData = change.doc.data();
String image = imageData?['url'];
imgs.add(CachedNetworkImageProvider(image));
});
setState(() {
images = imgs;
});
});}
I create ListView.build and try to fetch data using
_scrollListener() {
print(controller.position.extentAfter);
if (controller.position.extentAfter < 13) {
setState(() {
images.addAll(List.generate(2, (index) => 'Inserted $index'));
});
}_scrollListener() {
print(controller.position.extentAfter);
if (controller.position.extentAfter < 13) {
setState(() {
images.addAll(List.generate(2, (index) => 'Inserted $index'));
});
}}
#override
void
dispose() {
controller.removeListener(_scrollListener);
super.dispose();}
but i can't leazy load images that are storaged in this database collection 'galerytab1'
Question: How can i leazy load images from this collection'galerytab1' and display them in listview
Thank You!
setState will re-render your build method which causes the list and elements in the list to re-render as well. You can use KeyValue to prevent this from happening.
Also with modern flutter you can use NotificationListener instead of a ScrollController
This sample should give you a rough idea of how it works.
you can run it on dartpart
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: PaginationExample(
key: ValueKey('pagination'),
),
),
),
);
}
}
class PaginationExample extends StatefulWidget {
const PaginationExample({super.key});
#override
State<PaginationExample> createState() => PaginationExampleState();
}
class PaginationExampleState extends State<PaginationExample> {
List<String> urls = [];
#override
void initState() {
super.initState();
addUrls();
}
#override
void dispose() {
super.dispose();
}
void addUrls() {
final List<String> newUrls = List.generate(
10,
(_) {
int random = Random().nextInt(500) + 250; // 250-500
return 'https://picsum.photos/$random/$random';
},
);
setState(() {
urls.addAll(newUrls);
});
}
#override
Widget build(BuildContext context) {
return NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
if (notification.metrics.pixels ==
notification.metrics.maxScrollExtent) {
addUrls();
}
return true;
},
child: ListView.builder(
key: widget.key,
itemCount: urls.length,
itemExtent: 250,
itemBuilder: (context, index) {
return Image.network(
urls[index],
key: ValueKey(urls[index]),
);
},
),
);
}
}

Read data from Flutter via Bluetooth

I am trying to get the data from my bluetooth device. My problem is with the Flutter code to get such data.
services/sensor.dart
import 'dart:async';
import 'dart:convert' show utf8;
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:minertti/main.dart';
class SensorPage extends StatefulWidget {
const SensorPage({Key? key, required this.device}) : super(key: key);
final BluetoothDevice device;
#override
_SensorPageState createState() => _SensorPageState();
}
class _SensorPageState extends State<SensorPage> {
String service_uuid = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
String charaCteristic_uuid = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";
late bool isReady;
late Stream<List<int>> stream;
late List _temphumidata;
double _charge = 0;
double _data_1 = 0;
double _data_2 = 0;
#override
void initState() {
super.initState();
super.initState();
isReady = false;
connectToDevice();
}
void dispose() {
widget.device.disconnect();
super.dispose();
}
connectToDevice() async {
if (widget.device == null) {
_pop();
return;
}
new Timer(const Duration(seconds: 15), () {
if (!isReady) {
disconnectFromDevice();
_pop();
}
});
await widget.device.connect();
discoverServices();
}
disconnectFromDevice() {
if (widget.device == null) {
_pop();
return;
}
widget.device.disconnect();
}
discoverServices() async {
if (widget.device == null) {
_pop();
return;
}
List<BluetoothService> services = await widget.device.discoverServices();
services.forEach((service) {
if (service.uuid.toString().isNotEmpty) {
service.characteristics.forEach((characteristic) {
if (characteristic.uuid.toString().isNotEmpty) {
characteristic.setNotifyValue(!characteristic.isNotifying);
stream = characteristic.value;
setState(() {
isReady = true;
});
}
});
}
});
if (!isReady) {
_pop();
}
}
_pop() {
Navigator.of(context).pop(true);
}
String _dataParser(List<int> dataFromDevice) {
return utf8.decode(dataFromDevice);
}
#override
Widget build(BuildContext context) {
return Scaffold(
// appBar: AppBar(
// title: Text('dht11 Sensor'),
// ),
body: Container(
child: !isReady
? Center(
child: Text(
"Waiting...",
style: TextStyle(
fontSize: 24, color: Color.fromARGB(255, 0, 0, 0)),
),
)
: Container(
child: StreamBuilder<List<int>>(
stream: stream,
builder: (BuildContext context,
AsyncSnapshot<List<int>> snapshot) {
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
if (snapshot.connectionState == ConnectionState.active) {
var data = snapshot.data as List<int>;
var currentValue = _dataParser(data);
print("REALDATA: $data");
_temphumidata = currentValue.split(",");
//_charge = double.parse('${_temphumidata[0]}');
//_data_1 = double.parse('${_temphumidata[1]}');
//_data_2 = _temphumidata[2];
return DeviceScreen1(
device: widget.device,
//charge: _charge,
//data_2: _data_2,
//data_1: _data_1,
charge: 90,
data_1: "Data 1",
data_2: "Data 2");
} else {
return Text('Check the stream');
}
},
),
)),
);
}
}
var data = snapshot.data as List;
var currentValue = _dataParser(data);
They do not show values. But, from my Arduino I know that it does send/notify data. That is, my problem is with reading and obtaining said data.

Flutter: ListView not displaying anything + lazy loading

I am new in flutter and trying to create a listview with load more functionality.
Here is my class. It is not displaying anything, blank screen. List has data I am getting result in console.
class ReportPurchaseNew extends StatefulWidget {
final AdminUserDetails userDetails;
final String title;
const ReportPurchaseNew({Key key, this.title, this.userDetails})
: super(key: key);
#override
State<StatefulWidget> createState() => new ReportPurchaseState();
}
class ReportPurchaseState extends State<ReportPurchaseNew> {
String fromDate = "", toDate = "", usageType = "";
int limit = 7, offset = 0;
static int page = 0;
List<Result> _List = new List();
List<Result> _filteredList;
Future<PurchaseReport> _PurchaseReportResponse;
List<UsageResult> _usageList = [];
UsageResult _usageVal;
ScrollController _sc = new ScrollController();
bool isLoading = false;
//List users = new List();
#override
void initState() {
this._getMorePurchase(page);
super.initState();
_sc.addListener(() {
if (_sc.position.pixels ==
_sc.position.maxScrollExtent) {
_getMorePurchase(page);
}
});
}
#override
void dispose() {
_sc.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Lazy Load Large List"),
),
body: Container(
child: _buildList(),
),
resizeToAvoidBottomInset: false,
);
}
Widget _buildList() {
return ListView.builder(
itemCount: _List.length + 1, // Add one more item for progress indicator
padding: EdgeInsets.symmetric(vertical: 8.0),
itemBuilder: (BuildContext context, int index) {
if (index == _List.length) {
return _buildProgressIndicator();
} else {
return new ListTile(
leading: CircleAvatar(
radius: 30.0,
),
title :Text("my:"+(_List[index]
.product)),
subtitle: Text((_List[index]
.unitPrice)),
);
}
},
controller: _sc,
);
}
Widget _buildProgressIndicator() {
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child: new Opacity(
opacity: isLoading ? 1.0 : 00,
child: new CircularProgressIndicator(),
),
),
);
}
Future<PurchaseReport> getProjectDetails() async {
var result = await PurchaseReportRequest(
context,
widget.userDetails.result.raLoginId,
limit.toString(),
offset.toString(),
fromDate,
toDate,
_usageVal!=null ? _usageVal.name : "" ,
);
return result;
}
void _getMorePurchase(int index) async {
if (!isLoading) {
setState(() {
isLoading = true;
});
_PurchaseReportResponse = getProjectDetails();
setState(() {
isLoading = false;
_PurchaseReportResponse.then((response) {
if (response != null) {
_List.addAll(response.result);
page = page + limit;
print("printing length : "
+_List.length.toString());
for (int i = 0; i < response.result.length; i++) {
print('name:' +_List[i].product );
}
} else {
errorRaisedToast(context);
}
});
});
}
}
}
Try This,
if (response != null) {
List newList = new List();
// _List.addAll(response.result);
page = page + limit;
print("printing length : "
+_List.length.toString());
for (int i = 0; i < response.result.length; i++) {
newList.add(response.result[i]);
print('name:' +_List[i].product);
}
isLoading = false;
_List.addAll(newList);
page++;
} else {
errorRaisedToast(context);
}

Flutter load limited(20 documents) records and display in list view at a time

I have a requirement to read only 20 records at a time from Firestore and display in list view. When user click next button then I need to load next 20 documents. It is similar to paging.
Can some one help on how to do this. Any library available for this?
The below code limits the number of records to 3, it will load more records while scrolling the list instead of load more button starting from the last document retrieved from the cloud store
class Feed extends StatefulWidget {
Feed({this.firestore});
final Firestore firestore;
#override
_FeedState createState() => _FeedState();
}
class _FeedState extends State<Feed> {
ScrollController controller;
DocumentSnapshot _lastVisible;
bool _isLoading;
CollectionReference get homeFeeds => widget.firestore.collection('homefeed');
List<DocumentSnapshot> _data = new List<DocumentSnapshot>();
final scaffoldKey = GlobalKey<ScaffoldState>();
#override
void initState() {
controller = new ScrollController()..addListener(_scrollListener);
super.initState();
_isLoading = true;
_getData();
}
Future<Null> _getData() async {
// await new Future.delayed(new Duration(seconds: 5));
QuerySnapshot data;
if (_lastVisible == null)
data = await widget.firestore
.collection('homefeed')
.orderBy('created_at', descending: true)
.limit(3)
.getDocuments();
else
data = await widget.firestore
.collection('homefeed')
.orderBy('created_at', descending: true)
.startAfter([_lastVisible['created_at']])
.limit(3)
.getDocuments();
if (data != null && data.documents.length > 0) {
_lastVisible = data.documents[data.documents.length - 1];
if (mounted) {
setState(() {
_isLoading = false;
_data.addAll(data.documents);
});
}
} else {
setState(() => _isLoading = false);
scaffoldKey.currentState?.showSnackBar(
SnackBar(
content: Text('No more posts!'),
),
);
}
return null;
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
appBar: new AppBar(),
body: RefreshIndicator(
child: ListView.builder(
controller: controller,
itemCount: _data.length + 1,
itemBuilder: (_, int index) {
if (index < _data.length) {
final DocumentSnapshot document = _data[index];
return new Container(
height: 200.0,
child: new Text(document['question']),
);
}
return Center(
child: new Opacity(
opacity: _isLoading ? 1.0 : 0.0,
child: new SizedBox(
width: 32.0,
height: 32.0,
child: new CircularProgressIndicator()),
),
);
},
),
onRefresh: ()async{
_data.clear();
_lastVisible=null;
await _getData();
},
),
);
}
#override
void dispose() {
controller.removeListener(_scrollListener);
super.dispose();
}
void _scrollListener() {
if (!_isLoading) {
if (controller.position.pixels == controller.position.maxScrollExtent) {
setState(() => _isLoading = true);
_getData();
}
}
}
}
hope it helps