'Firebase onChildAdded adds duplicate entries to the list this makes the length of the list differ
My app is for the driver, who delivers orders through this application. In this, I am listening to all the orders assigned to the driver from the firebase realtime database. The onChildAdded.listen adds the order to a list named ongoingList of class Ongoing which means assigned to him. I am then displaying the length of the list as count in the dashboard. Now sometimes I am getting unexpected counts in the dashboard and also the list contains duplicate entries.
I am adding the code below
class Dashboard extends StatefulWidget {
const Dashboard({Key? key}) : super(key: key);
@override
_DashboardState createState() => _DashboardState();
}
class _DashboardState extends State<Dashboard>
with SingleTickerProviderStateMixin {
bool isLoading = false;
bool isOnline = true;
var OngoingDetails;
List<Ongoing> ongoingList = [];
List<OpenRequest> openRequestList = [];
DatabaseReference databaseReference = FirebaseDatabase.instance.reference();
late StreamSubscription<Event> ongoingStream;
late StreamSubscription<Event> openRequestStream;
late StreamSubscription<Event> removeOpenNodes;
late LocationData currentLoc;
double currentLat = 0;
double currentLng = 0;
DriverDetail _driverData = DriverDetail();
// late Timer timer;
@override
void initState() {
super.initState();
// timer =
// Timer.periodic(Duration(seconds: 300), (Timer t) => reloadPageAuto());
getDriverData();
countOpenRequest = 0;
ongoingCount = 0;
}
reloadPageAuto() {
// Navigator.pop(context); // pop current page
Navigator.pushReplacementNamed(context, '/dashboard'); // push it back in
}
getDriverData() async {
setState(() {
isLoading = true;
});
_driverData = await getDriverDetails();
print("${_driverData.driverName}");
setState(() {
isLoading = false;
});
//getCurrentLocation();
}
getCurrentLocation() async {
currentLoc = await getLoc();
setState(() {
currentLat = currentLoc.latitude!;
currentLng = currentLoc.longitude!;
isLoading = false;
});
// checkOpenRequest();
}
@override
void dispose() {
// timer.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
DateTime timeBackPressed = DateTime.now();
return isLoading == false
? DefaultTabController(
child: WillPopScope(
onWillPop: () async {
final difference = DateTime.now().difference(timeBackPressed);
timeBackPressed = DateTime.now();
if (difference >= Duration(seconds: 1)) {
final String msg = 'Press the back button again to exit';
showToast(msg);
return false;
} else {
Fluttertoast.cancel();
SystemNavigator.pop();
return true;
}
},
child: Scaffold(
appBar: AppBar(
leading: Switch(
materialTapTargetSize: MaterialTapTargetSize.padded,
activeTrackColor: Colors.grey,
value: isOnline,
activeColor: kWagonColour,
onChanged: (value) async {
setState(() {
isOnline = value;
//print(isOnline);
Fluttertoast.showToast(
msg: isOnline == true
? "You are now Online"
: "You are now Offline",
gravity: ToastGravity.BOTTOM,
textColor: Colors.white,
backgroundColor: kWagonColour,
);
});
if (isOnline == true) {
await OneSignal.shared.disablePush(false);
OneSignal.shared
.setAppId("abd31b6b-5fc4-4769-8684-224a439e422e");
final status = await OneSignal.shared.getDeviceState();
var playerId = status!.userId;
OSCreateNotification notification =
OSCreateNotification(
androidChannelId:
"1ff1eb80-0316-419f-bd37-0992145ee37d",
heading: "Go Wagon Driver",
playerIds: [playerId.toString()],
content: "Background Service Active",
androidSound: "onesignal_default_sound.wav",
iosSound: "onesignal_default_sound.wav",
);
OneSignal.shared.postNotification(notification);
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
));
} else {
//print('else');
await OneSignal.shared.disablePush(true);
}
},
),
actions: [
Padding(
padding: const EdgeInsets.only(right: 15.0),
child: GestureDetector(
child: CircleAvatar(
backgroundImage: NetworkImage(_driverData.image),
),
onTap: () {
Navigator.pushNamed(context, '/profile');
},
),
),
],
centerTitle: true,
title: Image.asset(
'images/app_icon.png',
height: 50.0,
width: 50.0,
),
bottom: TabBar(
tabs: [
Tab(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.home,
color: kWagonColour,
),
Padding(
padding: const EdgeInsets.only(left: 5),
child: Text('Home'),
),
],
),
),
Tab(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.price_change_outlined,
color: kWagonColour,
),
Padding(
padding: const EdgeInsets.only(left: 5),
child: Text('Earnings'),
),
],
),
),
],
labelColor: kWagonColour,
indicator: UnderlineTabIndicator(
borderSide: BorderSide(width: 2.0, color: kWagonColour),
insets: EdgeInsets.symmetric(horizontal: 25.0),
),
indicatorColor: kWagonColour,
unselectedLabelColor: Colors.grey,
indicatorSize: TabBarIndicatorSize.tab,
labelStyle: TextStyle(
fontSize: 16.0,
),
),
),
backgroundColor: Color(0xFFF5F5F5),
body: isLoading
? ColorLoader()
: GestureDetector(
child: TabBarView(
children: [
Status(
details: ongoingList,
),
Earnings(),
],
),
),
floatingActionButtonLocation:
FloatingActionButtonLocation.startFloat,
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => QRCodeScanner(),
));
},
child: Icon(
Icons.qr_code_scanner,
color: kWagonColour,
),
backgroundColor: Colors.white,
),
),
),
length: 2,
initialIndex: 0,
)
: Scaffold(
body: ColorLoader(),
);
}
}
class Status extends StatefulWidget {
const Status({Key? key, required this.details}) : super(key: key);
final List details;
@override
_StatusState createState() => _StatusState();
}
class _StatusState extends State<Status>
with AutomaticKeepAliveClientMixin<Status> {
@override
bool get wantKeepAlive => true;
var top = 10.0;
var left = 10.0;
DriverDetail _driverData = DriverDetail();
bool isLoading = false;
bool isLoadingCount = true;
List<Ongoing> ongoingList = [];
List<OpenRequest> openRequestList = [];
DatabaseReference databaseReference = FirebaseDatabase.instance.reference();
late StreamSubscription<Event> ongoingStream;
late StreamSubscription<Event> openRequestStream;
late StreamSubscription<Event> removeOpenNodes;
late LocationData currentLoc;
double currentLat = 0;
double currentLng = 0;
bool _enabled = true;
@override
void initState() {
super.initState();
getDriverData();
}
getCurrentLocation() async {
currentLoc = await getLoc();
setState(() {
currentLat = currentLoc.latitude!;
currentLng = currentLoc.longitude!;
});
setState(() {
isLoading = false;
});
checkOpenRequest();
}
checkOpenRequest() async {
print("checking open request");
if (countOpenRequest == 0) {
setState(() {
isOpenRequest = false;
});
}
print("open count $countOpenRequest");
countOpenRequest = 0;
openRequestStream = FirebaseDatabase.instance
.reference()
.child('shipments')
.child('open_requests')
.orderByChild('model_id')
.equalTo(double.parse(_driverData.modelId))
.onChildAdded.listen(_onEntryAddedOpen);
// .listen((event) {
// double total_distance = distance(
// currentLat,
// currentLng,
// double.parse(event.snapshot.value['pickup_latitude']),
// double.parse(event.snapshot.value['pickup_longitude']),
// 'K');
// print("distance for ${event.snapshot.key} $total_distance");
//
// if (total_distance <= 50) {
// HapticFeedback.heavyImpact();
// setState(() {
// // print("New request received: ${event.snapshot.value}");
// ++countOpenRequest;
// isOpenRequest = true;
// });
// }
// });
checkOngoing();
}
checkOngoing() async {
print("checking ongoing");
ongoingStream = FirebaseDatabase.instance
.reference()
.child('shipments')
.child('driver_shipments')
.child(_driverData.vehicleId)
.onChildAdded
.listen(_onEntryAddedOngoing);
setState(() {
isLoadingCount = false;
});
}
getDriverData() async {
setState(() {
isLoading = true;
});
_driverData = await getDriverDetails();
getCurrentLocation();
}
@override
void dispose() {
// timer.cancel();
openRequestStream.cancel();
ongoingStream.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
super.build(context);
var deviceWidth = MediaQuery.of(context).size.width;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 100.0,
padding: EdgeInsets.symmetric(vertical: 8.0),
width: double.infinity,
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AutoSizeText(
'Hi, ${_driverData.driverName}',
minFontSize: 16,
maxFontSize: 20,
overflow: TextOverflow.visible,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 10.0,
),
Text(
'What do you want to do today?',
style: TextStyle(
fontSize: 16.0,
),
),
],
),
SizedBox(
width: 50.0,
),
GestureDetector(
child: Icon(
Icons.replay_circle_filled,
color: kWagonColour,
size: 40.0,
semanticLabel: 'Refresh',
),
onTap: _enabled ? refreshCounts : null,
),
],
),
),
),
Container(
height: 100,
width: MediaQuery.of(context).size.width,
child: Stack(
children: [
Positioned(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
OngoingShipments(ongoingDetails: ongoingList),
),
);
},
child: Row(
children: [
Container(
width: deviceWidth / 7,
height: 40,
child: Center(
child: isLoadingCount == false
? Text(
ongoingList.length.toString(),
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
)
: CircularProgressIndicator(
color: Colors.white,
),
),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: kWagonColour,
),
),
SizedBox(
width: 5,
),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OngoingShipments(
ongoingDetails: ongoingList),
),
);
},
child: Text(
'ONGOING',
style: TextStyle(
color: kWagonColour,
),
),
style: ElevatedButton.styleFrom(
primary: Colors.white,
),
)
],
),
),
),
Positioned(
top: 20,
left: deviceWidth / 1.8,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TestFirebase()));
},
child: Row(
children: [
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TestFirebase()));
},
child: Text(
'OPEN',
style: TextStyle(
color: kWagonColour,
),
),
style: ElevatedButton.styleFrom(
primary: Colors.white,
),
),
SizedBox(
width: 5,
),
Container(
width: 60,
height: 40,
child: Center(
child: isLoadingCount == false
? Text(
openRequestList.length.toString(),
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
)
: CircularProgressIndicator(
color: Colors.white,
),
),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: kWagonColour,
),
),
],
),
),
),
],
),
),
],
),
);
}
refreshCounts() {
setState(() {
isLoadingCount = true;
_enabled = false;
});
isLoadingCount = true;
ongoingList = [];
openRequestList = [];
ongoingCount = 0;
countOpenRequest = 0;
Timer(Duration(seconds: 1), () {
setState(() {
_enabled = true;
});
checkOpenRequest();
});
}
_onEntryAddedOngoing(Event event) async {
setState(() {
ongoingList.add(Ongoing.fromSnapshot(event.snapshot));
});
}
_onEntryAddedOpen(Event event) async {
double totalDistance = distance(
currentLat,
currentLng,
double.parse(event.snapshot.value['pickup_latitude']),
double.parse(event.snapshot.value['pickup_longitude']),
'K');
print("distance for ${event.snapshot.key} $totalDistance");
if (totalDistance <= 50) {
HapticFeedback.heavyImpact();
setState(() {
openRequestList.add(OpenRequest.fromFirebase(event.snapshot));
});
}
}
}
Below is the code for my class Ongoing
Ongoing(
{this.baseFare,
this.cancelationFee,
this.customerId,
this.customerName,
this.distanceTotal,
this.driverId,
this.driverImage,
this.driverName,
this.driverNumber,
this.driverNumberCode,
this.dropAddress,
this.dropLatitude,
this.dropLongitude,
this.estimatedTime,
this.helpCount,
this.helpTotal,
this.isPayable,
this.itemCount,
this.masterFlag,
this.minHr,
this.minKm,
this.modelId,
this.payableFlag,
this.paymentMethod,
this.paymentStatus,
this.perHr,
this.perKm,
this.pickPayPaymentStatus,
this.pickupAddress,
this.pickupCode,
this.pickupLatitude,
this.pickupLongitude,
this.pickupTime,
this.price,
this.pricePerHr,
this.pricePerKm,
this.receiverName,
this.receiverPhone,
this.receiverPhoneCode,
this.senderName,
this.senderPhone,
this.senderPhoneCode,
this.shipmentId,
this.shipmentLabel,
this.shipmentLabelAr,
this.shipmentOtp,
this.shipmentPackageInstruction,
this.shipmentPackageName,
this.shipmentPackagePropertyId,
this.shipmentPackageTypeId,
this.shipmentPolyline,
this.status,
this.total,
this.type,
this.vehicleId,
this.vehicleName,
this.wagoncut,
this.isCashShipment,
this.invoiceNumber,
this.invoiceDate,
this.invoiceAmount,
this.operationMobile, this.packageName});
Ongoing.fromSnapshot(DataSnapshot snapshot) {
baseFare = snapshot.value['base_fare'];
cancelationFee = snapshot.value['cancelation_fee'];
customerId = snapshot.value['customer_id'];
customerName = snapshot.value['customer_name'];
distanceTotal = snapshot.value['distance_total'];
driverId = int.parse(snapshot.value['driver_id'].toString());
driverImage = snapshot.value['driver_image'];
driverName = snapshot.value['driver_name'];
driverNumber = snapshot.value['driver_number'];
driverNumberCode = snapshot.value['driver_number_code'];
dropAddress = snapshot.value['drop_address'];
dropLatitude = snapshot.value['drop_latitude'];
dropLongitude = snapshot.value['drop_longitude'];
estimatedTime = snapshot.value['estimated_time'];
helpCount = snapshot.value['help_count'];
helpTotal = snapshot.value['help_total'];
isPayable = snapshot.value['is_payable'];
itemCount = snapshot.value['item_count'];
masterFlag = snapshot.value['master_flag'];
minHr = snapshot.value['min_hr'];
minKm = snapshot.value['min_km'];
modelId = snapshot.value['model_id'];
payableFlag = snapshot.value['payable_flag'];
paymentMethod = snapshot.value['payment_method'];
paymentStatus = snapshot.value['payment_status'];
perHr = snapshot.value['per_hr'];
perKm = snapshot.value['per_km'];
pickPayPaymentStatus = snapshot.value['pick_pay_payment_status'];
pickupAddress = snapshot.value['pickup_address'];
pickupCode = snapshot.value['pickup_code'];
pickupLatitude = snapshot.value['pickup_latitude'];
pickupLongitude = snapshot.value['pickup_longitude'];
pickupTime = snapshot.value['pickup_time'];
price = snapshot.value['price'];
pricePerHr = snapshot.value['price_per_hr'];
pricePerKm = snapshot.value['price_per_km'];
receiverName = snapshot.value['receiver_name'];
receiverPhone = snapshot.value['receiver_phone'];
receiverPhoneCode = snapshot.value['receiver_phone_code'].toString();
senderName = snapshot.value['sender_name'];
senderPhone = snapshot.value['sender_phone'];
senderPhoneCode = snapshot.value['sender_phone_code'].toString();
shipmentId = snapshot.value['shipment_id'];
shipmentLabel = snapshot.value['shipment_label'];
shipmentLabelAr = snapshot.value['shipment_label_ar'];
shipmentOtp = snapshot.value['shipment_otp'];
shipmentPackageInstruction = snapshot.value['shipment_package_instruction'];
shipmentPackageName = snapshot.value['shipment_package_name'];
shipmentPackagePropertyId = snapshot.value['shipment_package_property_id'];
shipmentPackageTypeId = snapshot.value['shipment_package_type_id'];
shipmentPolyline = snapshot.value['shipment_polyline'];
status = snapshot.value['status'];
total = snapshot.value['total'];
type = snapshot.value['type'];
vehicleId = snapshot.value['vehicle_id'];
vehicleName = snapshot.value['vehicle_name'];
wagoncut = snapshot.value['wagoncut'];
isCashShipment = snapshot.value['is_cash_shipment'].toString();
invoiceAmount = snapshot.value['invoice_amount'].toString();
invoiceNumber = snapshot.value['invoice_no'].toString();
invoiceDate = snapshot.value['invoice_date'].toString();
operationMobile = snapshot.value['operation_mobile'].toString();
}
}
If anyone has relevant suggestion regarding it, please help me through it. Thank you in advance
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|