flutterfire
flutterfire copied to clipboard
[firebase_database]: DatabaseReference.once() does not complete when an onValue listener is active on the same reference in firebase_database 11.1.4 (Flutter Web only)
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
- When using firebase_database version 11.0.0 and above on Flutter Web, calling once() on a DatabaseReference that already has an active onValue listener causes the Future returned by once() to never complete.
- This issue does not occur on iOS or Android platforms.
- In firebase_database versions 10.5.7 and below, everything works as expected on all platforms.
Reproducing the issue
Minimal Example
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_database/firebase_database.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
// Add your Firebase config here
);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FirebaseWebIssueScreen(),
);
}
}
class FirebaseWebIssueScreen extends StatefulWidget {
@override
_FirebaseWebIssueScreenState createState() => _FirebaseWebIssueScreenState();
}
class _FirebaseWebIssueScreenState extends State<FirebaseWebIssueScreen> {
String? value1;
String? value2;
StreamSubscription<DatabaseEvent>? _subscription;
@override
void initState() {
super.initState();
// Start listening to value1
_subscription = FirebaseDatabase.instance
.ref('/testValue')
.onValue
.listen((event) {
setState(() {
value1 = event.snapshot.value as String?;
});
});
}
@override
void dispose() {
_subscription?.cancel();
super.dispose();
}
Future<void> _updateValue2() async {
// Try to get value2 once
try {
final data = await FirebaseDatabase.instance
.ref('/testValue')
.once();
setState(() {
value2 = data.snapshot.value as String?;
});
} catch (e) {
print('Error fetching value2: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Firebase Database Issue'),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Value1: $value1'),
SizedBox(height: 20),
ElevatedButton(
onPressed: _updateValue2,
child: Text('Update Value 2'),
),
SizedBox(height: 20),
Text('Value2: $value2'),
],
),
));
}
}
Steps to Reproduce the Issue
1. Set Up Firebase:
- Initialize Firebase correctly in your Flutter Web app.
- In your Firebase Realtime Database, add a test value at /testValue. For example, set /testValue to "Hello World".
2. Run the Simplified App:
- Use the updated code provided above.
- Ensure your pubspec.yaml includes firebase_database: 11.1.4
3. Observe the Behavior on Flutter Web:
- The app starts and displays Value1, which updates correctly via the onValue listener.
- Tap the "Update Value 2" button.
- Value2 remains null because the once() call never completes. Test on iOS or Android:
4. Run the same app on an iOS or Android device or simulator.
- Tap the "Update Value 2" button.
- Value2 updates correctly, indicating that once() completes as expected on these platforms.
- Test with Older Version on Flutter Web:
5. Downgrade firebase_database to 10.5.7 in your pubspec.yaml.
- Run the app again on Flutter Web.
- This time, Value2 updates correctly after tapping the button.
Expected Behavior
- Tapping "Update Value 2" should fetch the value from the database and display it under Value2 on all platforms, including Flutter Web.
Actual Behavior
- With firebase_database 11.0.0 and above on Flutter Web, Value2 remains null because once() does not complete when there is an active onValue listener on the same reference.
Firebase Core version
3.6.0
Flutter Version
3.24.3
Relevant Log Output
No error logs are generated when the issue occurs. The Future returned by once() remains pending indefinitely.
Flutter dependencies
Expand Flutter dependencies snippet
Replace this line with the contents of your `flutter pub deps -- --style=compact`.
Additional context and comments
- No exceptions or error messages are shown in the console.
- The issue appears to be specific to Flutter Web when using firebase_database 11.0.0 and above.
- Downgrading to firebase_database version 10.5.7 resolves the issue on Flutter Web.
- This suggests a potential regression or platform-specific issue introduced in version 11.0.0.
Hi @BWhiteApps , thanks for the report. I'm able to reproduce this issue. However, It doesn't seem to be any different on version 10.5.7 in my case.
Reproducible code
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
if (USE_DATABASE_EMULATOR) {
FirebaseDatabase.instance.useDatabaseEmulator(emulatorHost, emulatorPort);
}
runApp(
MaterialApp(
title: 'Flutter Database Example',
home: FirebaseWebIssueScreen(),
),
);
}
class FirebaseWebIssueScreen extends StatefulWidget {
@override
_FirebaseWebIssueScreenState createState() => _FirebaseWebIssueScreenState();
}
class _FirebaseWebIssueScreenState extends State<FirebaseWebIssueScreen> {
int? value1;
int? value2;
StreamSubscription<DatabaseEvent>? _subscription;
@override
void initState() {
super.initState();
// Start listening to value1
_subscription =
FirebaseDatabase.instance.ref('counter').onValue.listen((event) {
setState(() {
value1 = event.snapshot.value as int?;
});
});
}
@override
void dispose() {
_subscription?.cancel();
super.dispose();
}
Future<void> _updateValue2() async {
// Try to get value2 once
try {
final data = await FirebaseDatabase.instance.ref('counter').once();
setState(() {
value2 = data.snapshot.value as int?;
});
} catch (e) {
print('Error fetching value2: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Firebase Database Issue'),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Value1: $value1'),
SizedBox(height: 20),
ElevatedButton(
onPressed: _updateValue2,
child: Text('Update Value 2'),
),
SizedBox(height: 20),
Text('Value2: $value2'),
],
),
));
}
}
@SelaseKay Please try using the minimal example I provided. We have heavily tested this problem as we have 2 different web apps that are stuck on 10.5.7 due to this issue and would like to upgrade them both. Whenever we upgrade them to 11.0.0 and above multiple parts of our apps break due to this specific issue. A work around is to use .get() instead of .once() but using .get() comes with its own set of problems so we are stuck until this gets resolved.
Thanks @BWhiteApps , It seems to work fine on version 10.5.7.
It appears that the problem line in the firebase_database package is here: https://github.com/firebase/flutterfire/commit/e298cb4e5750a75c458acd907959b256a7f1d40d#diff-19abf2f5278bb16502160289df7e12535d5ab9c7a2e62ff6870537db777406dcR486
If I remove the line that uses sync: true from database.dart then my example behaves like it should. I believe this line is responsible for other bug reports as well such as: https://github.com/firebase/flutterfire/issues/13003