I would like to reduce the number of read usage in FirebaseFirestore. As I am trying to load the FireStore Data in StreamBuilder. StreamBuilder connects with FireStore everytime whenever the app restarts, it is increasing the number of read usage. Is there a way to optimize the Firestore read usage?
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'LoginScreen.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FlutterFire Samples',
debugShowCheckedModeBanner: false,
theme:
ThemeData(primarySwatch: Colors.indigo, brightness: Brightness.dark),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
//Initializing
final CollectionReference _products =
FirebaseFirestore.instance.collection('products');
final _productsStream = _products.snapshots();
// Source can be CACHE, SERVER, or DEFAULT.
final TextEditingController _nameController = TextEditingController();
final TextEditingController _priceController = TextEditingController();
Future<void> _create([DocumentSnapshot? documentSnapshot]) async {
await showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (BuildContext ctx) {
return Padding(
padding: EdgeInsets.only(
top: 20,
left: 20,
right: 20,
bottom: MediaQuery.of(ctx).viewInsets.bottom + 20),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
controller: _nameController,
decoration: const InputDecoration(labelText: 'Name'),
),
TextField(
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: _priceController,
decoration: const InputDecoration(
labelText: 'Price',
),
),
const SizedBox(
height: 20,
),
ElevatedButton(
child: const Text('Create'),
onPressed: () async {
//var i = 0;
//for (i = i; i < 10000; i++) {
// final String name;
// final double? price;
double.tryParse(_priceController.text);
// if (price != null) {
await _products.add({
"name": _nameController.text,
"price": _priceController.text
});
// }
_nameController.text = '';
_priceController.text = '';
Navigator.of(context).pop();
//}
},
)
],
),
);
});
}
Future<void> _update([DocumentSnapshot? documentSnapshot]) async {
if (documentSnapshot != null) {
_nameController.text = documentSnapshot['name'];
_priceController.text = documentSnapshot['price'].toString();
}
await showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (BuildContext ctx) {
return Padding(
padding: EdgeInsets.only(
top: 20,
left: 20,
right: 20,
bottom: MediaQuery.of(ctx).viewInsets.bottom + 20),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
controller: _nameController,
decoration: const InputDecoration(labelText: 'Name'),
),
TextField(
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
controller: _priceController,
decoration: const InputDecoration(
labelText: 'Price',
),
),
const SizedBox(
height: 20,
),
ElevatedButton(
child: const Text('Update'),
onPressed: () async {
final String name = _nameController.text;
final double? price =
double.tryParse(_priceController.text);
if (price != null) {
await _products
.doc(documentSnapshot!.id)
.update({"name": name, "price": price});
_nameController.text = '';
_priceController.text = '';
Navigator.of(context).pop();
}
},
),
],
),
);
});
}
Future<void> _delete(String productId) async {
await _products.doc(productId).delete();
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('You have successfully deleted a product')));
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
// stream: _products.snapshots(),
stream: _productsStream,
builder: (context, AsyncSnapshot<QuerySnapshot> streamSnapshot) {
if (streamSnapshot.hasData) {
return ListView.builder(
itemCount: streamSnapshot.data!.docs.length,
itemBuilder: (context, index) {
final DocumentSnapshot documentSnapshot =
streamSnapshot.data!.docs[index];
return Card(
margin: EdgeInsets.all(10),
child: ListTile(
title: Text(documentSnapshot['name']),
subtitle: Text(documentSnapshot['price'].toString()),
trailing: SizedBox(
width: 100,
child: Row(children: [
IconButton(
onPressed: () => _update(documentSnapshot),
icon: Icon(Icons.edit),
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () => _delete(documentSnapshot.id)),
]),
),
),
);
},
);
}
return const Center(
child: CircularProgressIndicator(),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => _create(),
child: const Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}