flutterfire
flutterfire copied to clipboard
[firebase_database]: Issue on web debug mode when listening to multiple onValue streams on the same path
Is there an existing issue for this?
- [X] I have searched the existing issues.
Which plugins are affected?
Database
Which platforms are affected?
Web
Description
Listening to the same path multiple times will only return a result to the latest stream. However it must return a result to all streams i.e stream 1 & stream 2 print statements must get displayed.
This issue is present on web platform in DEBUG mode. The console display the following:
got stream 3 with value:null
got stream 3 with value:1
got stream 3 with value:2
When running in RELEASE mode there is no issue. The chrome console displays the following:
got stream 1 with value:2 js_primitives.dart:42
got stream 2 with value:2 js_primitives.dart:42
got stream 3 with value:2 js_primitives.dart:42
got stream 1 with value:3 js_primitives.dart:42
got stream 2 with value:3 js_primitives.dart:42
got stream 3 with value:3 js_primitives.dart:42
got stream 1 with value:4 js_primitives.dart:42
got stream 2 with value:4 js_primitives.dart:42
got stream 3 with value:4 js_primitives.dart:42
Lastly this worked fine in firebase_database 10.5.0 with firebase_core: 2.28.0 but is now broken in firebase_database: 11.0.4 with firebase_core 3.3.0.
Reproducing the issue
Run the code sample & increment the counter:
import 'dart:async';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'firebase_options.dart';
void main() async {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// returns the counter value
Stream<int?> _getCounterValue() {
return FirebaseDatabase.instance
.ref()
.child('/counter')
.onValue
.map((event) {
final result = event.snapshot.value;
return result as int?;
});
}
int _counter = 0;
// streams to listen to counter value
StreamSubscription<int?>? _stream1, _stream2, _stream3;
@override
void initState() {
super.initState();
_stream1 = _getCounterValue().listen((value) {
print('got stream 1 with value:$value');
_updateCounter(value);
});
_stream2 = _getCounterValue().listen((value) {
print('got stream 2 with value:$value');
_updateCounter(value);
});
_stream3 = _getCounterValue().listen((value) {
print('got stream 3 with value:$value');
_updateCounter(value);
});
}
void _updateCounter(int? value) {
if (!mounted) return;
setState(() => _counter = value ?? 0);
}
void _incrementCounter() {
_counter++;
FirebaseDatabase.instance.ref().child('/counter').set(_counter);
}
@override
void dispose() {
_stream1?.cancel();
_stream2?.cancel();
_stream3?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
Firebase Core version
3.3.0
Flutter Version
3.19.6
Relevant Log Output
Launching lib/main.dart on Chrome in debug mode...
Waiting for connection from debug service on Chrome...
This app is linked to the debug service: ws://127.0.0.1:64942/82TkgPvGJ0s=/ws
Debug service listening on ws://127.0.0.1:64942/82TkgPvGJ0s=/ws
Debug service listening on ws://127.0.0.1:64942/82TkgPvGJ0s=/ws
got stream 3 with value:null
got stream 3 with value:1
got stream 3 with value:2
Flutter dependencies
Expand Flutter dependencies snippet
Dart SDK 3.3.4
Flutter SDK 3.19.6
web_debug_mode_issue 1.0.0+1
dependencies:
- cupertino_icons 1.0.8
- firebase_core 3.3.0 [firebase_core_platform_interface firebase_core_web flutter meta]
- firebase_database 11.0.4 [firebase_core firebase_core_platform_interface firebase_database_platform_interface firebase_database_web flutter]
- flutter 0.0.0 [characters collection material_color_utilities meta vector_math sky_engine]
dev dependencies:
- flutter_lints 3.0.2 [lints]
- flutter_test 0.0.0 [flutter test_api matcher path fake_async clock stack_trace vector_math leak_tracker_flutter_testing async boolean_selector characters collection leak_tracker leak_tracker_testing material_color_utilities meta source_span stream_channel string_scanner term_glyph vm_service]
transitive dependencies:
- _flutterfire_internals 1.3.40 [collection firebase_core firebase_core_platform_interface flutter meta]
- async 2.11.0 [collection meta]
- boolean_selector 2.1.1 [source_span string_scanner]
- characters 1.3.0
- clock 1.1.1
- collection 1.18.0
- fake_async 1.3.1 [clock collection]
- firebase_core_platform_interface 5.2.0 [collection flutter flutter_test meta plugin_platform_interface]
- firebase_core_web 2.17.4 [firebase_core_platform_interface flutter flutter_web_plugins meta web]
- firebase_database_platform_interface 0.2.5+40 [_flutterfire_internals collection firebase_core flutter meta plugin_platform_interface]
- firebase_database_web 0.2.5+12 [collection firebase_core firebase_core_web firebase_database_platform_interface flutter flutter_web_plugins]
- flutter_web_plugins 0.0.0 [flutter characters collection material_color_utilities meta vector_math]
- leak_tracker 10.0.0 [clock collection meta path vm_service]
- leak_tracker_flutter_testing 2.0.1 [flutter leak_tracker leak_tracker_testing matcher meta]
- leak_tracker_testing 2.0.1 [leak_tracker matcher meta]
- lints 3.0.0
- matcher 0.12.16+1 [async meta stack_trace term_glyph test_api]
- material_color_utilities 0.8.0 [collection]
- meta 1.11.0
- path 1.9.0
- plugin_platform_interface 2.1.8 [meta]
- sky_engine 0.0.99
- source_span 1.10.0 [collection path term_glyph]
- stack_trace 1.11.1 [path]
- stream_channel 2.1.2 [async]
- string_scanner 1.2.0 [source_span]
- term_glyph 1.2.1
- test_api 0.6.1 [async boolean_selector collection meta source_span stack_trace stream_channel string_scanner term_glyph]
- vector_math 2.1.4
- vm_service 13.0.0
- web 0.5.1
Additional context and comments
This issue has been reported previously here. I also added a comment to that issue. However the issue was locked.
So I have opened a new issue with sample code to reproduce it.
We also have this issue - seems to only be on web. We have had to lock our firebase_database to 10.5.7, everything higher than this is broken.
@Lyokone Is there a way to track when this fix will be released? It is still broken for us on firebase_database: 11.1.3 and it is preventing us from updating our firebase packages.
@bwhiteFC Are you using Riverpods by any chance? We had this problem and determined that it was actually due to an issue in the latest release of that package and had to roll back to flutter_riverpod version 2.0.0.
@ansells @Lyokone no I'm not using riverpods. This is specifically an issue on web only where if you have the following code:
Future<String?> getUserName() async {
final snapshot = await _databaseReference
.child('users/$userId/name')
.once();
return snapshot.snapshot.value as String?;
}
Stream<String?> get observeUserName => _databaseReference
.child('users/$userId/name')
.onValue.map((event) => event.snapshot.value as String?);
// Somewhere in the project you have:
final subscription = observeUserName.listen((event) => print(event));
// Somewhere later in the project you have:
final name = await getUserName();
print(name);
Doing this, getUserName() will never return because ever gets put into the stream so once() doesn't work like it should. This works fine on Android and iOS but it is broken in web starting with firebase_database 11.0.0.