I found some issue thread with people also not being able to complete transactions, but it does not even provide solutions.
Problem
Suddenly, my transactions crashes when using transaction.get.
runTransaction(
(Transaction transaction) async {
await transaction.get(documentReference); // "Timed out waiting for Task"
}
The PlatformException does also not really help me because it crashes in platform_channel...
E/flutter (16297): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter (16297): PlatformException(Error performing transaction, Timed out waiting for Task, null)
E/flutter (16297): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:547:7)
E/flutter (16297): #1 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:279:18)
E/flutter (16297): <asynchronous suspension>
E/flutter (16297): #2 Firestore.runTransaction (file:///G:/flutter/.pub-cache/hosted/pub.dartlang.org/cloud_firestore-0.7.3/lib/src/firestore.dart:115:10)
// here comes another <asynchronous suspension> followed by my code
This comes from Android.
This Error comes sometimes because:
don't debug the transaction while it's running, so put the breakpoint in a proper line before or after.
Another errors come because you don't :
do all get calls first, then your write or update comes.
as Firestore document said:
"Read operations must come before write operations."
https://firebase.google.com/docs/firestore/manage-data/transactions#transactions
The issue I was having has since been fixed by the cloud_firestore team.
If you are still experiencing a similar issue, you should either ask a question here on StackOverflow or create an issue.
Note: You can also make atomic changes to data using transactions.
While this is a bit heavy-handed for incrementing a vote total, it is
the right approach for more complex changes. Here is what a
transaction that updated the votes count might look like.
onTap: () => Firestore.instance.runTransaction((transaction) async {
final freshSnapshot = await transaction.get(record.reference);
final fresh = Record.fromSnapshot(freshSnapshot);
await transaction
.update(record.reference, {'votes': fresh.votes + 1});
}),
How does this work? By wrapping the read and write operations in one
transaction, you're telling Cloud Firestore to only commit a change if
there was no external change to the underlying data while the
transaction was running. If two users aren't concurrently voting on
that particular name, the transaction runs exactly once. But if the
number of votes changes between the transaction.get(...) and the
transaction.update(...) calls, the current run isn't committed, and
the transaction is retried. After 5 failed retries, the transaction
fails.
Source
https://codelabs.developers.google.com/codelabs/flutter-firebase/index.html#10
This works without any problems:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
Future<void> main() async {
final FirebaseApp app = await FirebaseApp.configure(
name: 'yourappname',
options: const FirebaseOptions(
googleAppID: 'yourgoogleid',
gcmSenderID: 'yourgmssenderid',
apiKey: 'yourapikey',
projectID: 'yourprojectid',
),
);
final Firestore firestore = Firestore(app: app);
await firestore.settings(
timestampsInSnapshotsEnabled: true,
persistenceEnabled: true,
sslEnabled: true
);
runApp(MaterialApp(
title: 'Firestore Example', home: MyHomePage(firestore: firestore)));
}
class MessageList extends StatelessWidget {
MessageList({this.firestore});
final Firestore firestore;
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: firestore.collection('messages').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return const Text('Loading...');
final int messageCount = snapshot.data.documents.length;
return ListView.builder(
itemCount: messageCount,
itemBuilder: (_, int index) {
final DocumentSnapshot document = snapshot.data.documents[index];
return ListTile(
title: Text(document['message'] ?? '<No message retrieved>'),
subtitle: Text('Message ${index + 1} of $messageCount'),
);
},
);
},
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({this.firestore});
final Firestore firestore;
CollectionReference get messages => firestore.collection('messages');
Future<void> _addMessage() async {
final DocumentReference postRef = firestore.document('posts/123');
firestore.runTransaction((Transaction tx) async {
DocumentSnapshot postSnapshot = await tx.get(postRef);
if (postSnapshot.exists) {
await tx.update(postRef, <String, dynamic>{'likesCount': postSnapshot.data['likesCount'] + 1});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Firestore Example'),
),
body: MessageList(firestore: firestore),
floatingActionButton: FloatingActionButton(
onPressed: _addMessage,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
Related
When I am tapping on the blank screen to cancel the sign in. I am getting endless loading screen. I am not able to figure out how to dismiss the progress Indicator upon cancelling.
Here's code for Google sign in:
final googleSignIn = GoogleSignIn();
Future signInGoogle() async {
try {
final GoogleSignInAccount? googleUser = await googleSignIn.signIn();
final GoogleSignInAuthentication? googleAuth =
await googleUser?.authentication;
final OAuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth?.accessToken,
idToken: googleAuth?.idToken,
);
final UserCredential userCredential =
await _firebaseAuth.signInWithCredential(credential);
final User? user = userCredential.user;
return _userFromFirebase(user);
} on FirebaseAuthException catch (e) {
return e.message ?? e.toString();
}
}
On Welcome screen I'm using bool isLoading to show progress indicator. When result == null, I'm using setState to set isLoading = false but it is not working for me. It shows loading screen endlessly. Do you know what I have to do to show welcome screen upon cancelling sign in.
Here's code for Welcome Screen:
bool isLoading = false;
isLoading
? const Center(child: CircularProgressIndicator.adaptive())
: Scaffold(
appBar: CupertinoNavigationBar(middle: navbarLogo()),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0),
child: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Spacer(),
Center(
child: Text('Discover',
style: Theme.of(context).textTheme.headline4,
textAlign: TextAlign.center),
),
Spacer(),
///Google Sign In Button
SignInButton(
widget:
Image.asset('images/google-logo.png', height: 22.0),
title: 'Continue with Google',
onTap: () async {
try {
setState(() => isLoading = true);
final result =
await _database.signInGoogle().then((value) {
Navigator.of(context).pushNamedAndRemoveUntil(
HomeScreen.id,
ModalRoute.withName(HomeScreen.id));
});
if (result == null) {
setState(() => isLoading = false);
if (kDebugMode) {
print('error signing in');
}
}
} on Exception catch (e) {
if (kDebugMode) {
print(e);
}
}
}),
UPDATE: The thing is everything was working fine before this. Location Provider was also working fine. When I did that, It crashed suddenly with this error.
Error:
Unhandled Exception: Error: Could not find the correct Provider above this FeedScreen Widget
E/flutter (11935): This happens because you used a BuildContext that does not include the provider
E/flutter (11935): of your choice. There are a few common scenarios:
E/flutter (11935):
E/flutter (11935): - You added a new provider in your main.dart and performed a hot-reload.
E/flutter (11935): To fix, perform a hot-restart.
E/flutter (11935): - The provider you are trying to read is in a different route.
E/flutter (11935): Providers are "scoped". So if you insert of provider inside a route, then
E/flutter (11935): other routes will not be able to access that provider.
E/flutter (11935): - You used a BuildContext that is an ancestor of the provider you are trying to read.
E/flutter (11935): Make sure that FeedScreen is under your MultiProvider/Provider.
E/flutter (11935): This usually happens when you are creating a provider and trying to read it immediately.
Sign out issue Edit:
This is my sign out method in Auth Screen:
Future signOut() async {
try {
await _firebaseAuth.signOut();
await googleSignIn.disconnect();
await googleSignIn.signOut();
} on Exception catch (e) {
print(e.toString());
return null;
}
}
In Account Screen I'm call this signOut() method:
TextButton(
onPressed: () {
_authService.signOut();
},
child: Text('Sign Out'),
),
I'm wrapping my initialRoute with WrapperScreen where I'm checking If currentUser == null ? WelcomeScreen() : HomeScreen ();
But when I click on Sign out. I get Signed out but I'm not getting redirected to WelcomeScreen which I should as I'm checking that on Wrapper Screen. Do you know what I am doing wrong. I'm really grateful for all your help.
The thing here is that you are always returning some value from your signInGoogle() method, so the value of result in your Welcome screen would never be null. Try this instead:
Modify your signInGoogle to return null if google sign in is not successful and also on any exception as:
Future signInGoogle() async {
try {
final GoogleSignInAccount? googleUser = await googleSignIn.signIn();
if(googleUser == null){
return null;
}
final GoogleSignInAuthentication? googleAuth =
await googleUser?.authentication;
final OAuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth?.accessToken,
idToken: googleAuth?.idToken,
);
final UserCredential userCredential =
await _firebaseAuth.signInWithCredential(credential);
final User? user = userCredential.user;
return _userFromFirebase(user);
} on FirebaseAuthException catch (e) {
return null;
//return e.message ?? e.toString();
}
}
This question already has answers here:
No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp() in Flutter and Firebase
(27 answers)
Closed 1 year ago.
Error : no firebase app has been created call firebase.initializeapp
My Question : Where should i need to add firebase initialization
A stateless widget with firestore reference 'users'
class FeedBack extends StatelessWidget {
CollectionReference users = FirebaseFirestore.instance.collection('users');
late String txtnote;
late String note;
#override
Widget build(BuildContext context) {
return Scaffold(
onpress integration for writing data to firestore
child: ElevatedButton(
onPressed: () async {
await users.add({
'subject': note,
'email': 'example#gmail.com',
'description': txtnote
}).then((value) => print('Data Added Successfully!'));
},
child: Text(
'Submit',
style: TextStyle(color: Colors.white),
),
Note : This dart file 'feedback.dart' does not contain void main function its a stateless widget
You can call inside the main entry point of your app:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
As a default, this should go in the main.dart file
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
I'm trying to delete document in firestore with this function,
[UPDATE] following code from the documentation
class DatabaseService {
final String uid;
final String taskId;
final String boardId;
DatabaseService({this.uid, this.taskId, this.boardId});
///delete task
Future<void> deleteTask() async {
return await FirebaseFirestore.instance
.collection('user')
.doc(uid)
.collection('tasks')
.doc(taskId)
.delete()
.then((value) => print('task $taskId deleted'))
.catchError((error) => print("Failed to delete task: $error"));
}
}
I put wrong collection name, supposedly tasks. I already update with the right name.
trigger button:
IconButton(
icon: Icon(
Icons.delete_outline,
color: kColorRed,
),
onPressed: () async {
print('task delete pressed');
print(widget.userId);
print(widget.taskId);
await DatabaseService(uid: widget.userId, taskId: widget.taskId)
.deleteTask();
Navigator.pop(context);
}),
output:
flutter: task delete pressed
flutter: VWtHv8LPE3brezl9a5zmHlwYM5h2
flutter: [#9bb27]
flutter: VWtHv8LPE3brezl9a5zmHlwYM5h2 task [#9bb27] deleted
inside the document:
it back with the print result. But, when I checked on Firestore, the document still there.
Am I doing it right?
I got the same problem .
I have solve this by check userid is passing or not .I mean getting the value for userid
I am trying get User Name through a document stored in users collection in cloud firestore but my build method runs before the data is received.
The initState(){} method does not wait for uidDetails() to complete and therefore null values are passed in DoctorListStream(currentUserName) . Since the initState(){}` method cannot be made async I want to know what can be done to fix this. I have also tried to implement both StreamBuilder and FutureBuilder but failed.
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import '../components/doc_list_retriever.dart';
class ListOfDoctors extends StatefulWidget {
#override
_ListOfDoctorsState createState() => _ListOfDoctorsState();
}
class _ListOfDoctorsState extends State<ListOfDoctors> {
final _auth = FirebaseAuth.instance;
final _fStore = Firestore.instance;
String currentUserUid;
String currentUserName;
#override
void initState() {
// TODO: implement initState
super.initState();
uidDetails();
}
void uidDetails() async {
final FirebaseUser user = await _auth.currentUser();
currentUserUid = user.uid;
print(currentUserUid + 'from user details');
await Firestore.instance
.collection('users')
.document(currentUserUid)
.get()
.then((DocumentSnapshot) {
currentUserName = DocumentSnapshot.data['name'].toString();
});
print(currentUserName + ' from uid Details');
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF1D1E33),
body: SafeArea(
child: Column(
children: <Widget>[
Text(
'Doctors:',
textAlign: TextAlign.left,
style: TextStyle(fontSize: 40, color: Colors.white70),
),
DoctorListStream(currentUserName),
],
),
),
);
}
}
CONSOLE :
Performing hot restart...
Syncing files to device AOSP on IA Emulator...
Restarted application in 848ms.
I/BiChannelGoogleApi(27263): [FirebaseAuth: ] getGoogleApiForMethod() returned Gms: com.google.firebase.auth.api.internal.zzaq#95a83d7
D/FirebaseAuth(27263): Notifying id token listeners about user ( 5TlH5zoCqfWDNDlAgvIsc5yAHPA3 ).
I/flutter (27263): 5TlH5zoCqfWDNDlAgvIsc5yAHPA3from user details
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building StreamBuilder<QuerySnapshot>(dirty, state: _StreamBuilderBaseState<QuerySnapshot, AsyncSnapshot<QuerySnapshot>>#044e7):
The method '+' was called on null.
Receiver: null
Tried calling: +(" from doctor list stream")
The relevant error-causing widget was:
StreamBuilder<QuerySnapshot> file:///D:/projects/clinic/lib/components/doc_list_retriever.dart:14:12
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1 DoctorListStream.build.<anonymous closure> (package:clinic/components/doc_list_retriever.dart:26:27)
#2 StreamBuilder.build (package:flutter/src/widgets/async.dart:509:81)
#3 _StreamBuilderBaseState.build (package:flutter/src/widgets/async.dart:127:48)
#4 StatefulElement.build (package:flutter/src/widgets/framework.dart:4623:28)
...
════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter (27263): Dhruv from uid Details
════════ Exception caught by rendering library ═════════════════════════════════════════════════════
A RenderFlex overflowed by 99670 pixels on the bottom.
The relevant error-causing widget was:
Column file:///D:/projects/clinic/lib/screens/list_of_doctors.dart:43:16
════════════════════════════════════════════════════════════════════════════════════════════════════
I would opt to using a stream builder to get the user data. sample implementation
String username;
body: StreamBuilder(
stream: Firestore.instance
.collection('users')
.document(userid)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SpinKitDoubleBounce(
color: Colors.blue,
);
}
var userDoc = snapshot.data;
userName = userDoc["name"];
return .... //your other widgets
I have an issue with firebase and flutter. I'm building app with signing in and displaying list of expenses from collection, which name is user id. When the user signs in, he will see list with items from his collection. I used Stream method. The problem is that before user signs in, stream recieves null id and the app crashes. Is there any way to set this stream after user signs in? I will be thankful for any help!
This is the error
The following assertion was thrown building Home(dirty):
'package:cloud_firestore/src/firestore.dart': Failed assertion: line 72 pos 12: 'path != null': is not true.
Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new?template=BUG.md
The relevant error-causing widget was
Home
lib\screens\wrapper.dart:18
When the exception was thrown, this was the stack
#2 Firestore.collection
package:cloud_firestore/src/firestore.dart:72
#3 DatabaseService.expenses
package:expenses_app/services/database.dart:38
#4 Home.build
package:expenses_app/…/home/home.dart:27
#5 StatelessElement.build
package:flutter/…/widgets/framework.dart:4291
#6 ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:4223
this is stream in database file
Stream<QuerySnapshot> get expenses {
return firestoreReference.collection(uid).snapshots();
}
this is widget, which loads after user signs in
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:expenses_app/services/auth.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:expenses_app/services/database.dart';
import 'package:provider/provider.dart';
import 'expenses_list.dart';
class Home extends StatelessWidget {
static String currentUid;
final AuthService _auth = AuthService();
final FirebaseAuth firebaseAuth = FirebaseAuth.instance;
void getUid() async {
final FirebaseUser user = await firebaseAuth.currentUser();
currentUid = user.uid;
//print(currentUid);
}
#override
Widget build(BuildContext context) {
getUid();
return StreamProvider<QuerySnapshot>.value(
value: DatabaseService(uid: currentUid).expenses,
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.red[400],
title: Text('Expenses App'),
elevation: 0.0,
actions: <Widget>[
FlatButton.icon(
icon: Icon(Icons.person,
color: Colors.white,),
onPressed: () async {
await _auth.signOut();
},
label: Text('Logout',
style: TextStyle(color: Colors.white),),
)
],
),
body: ExpensesList(),
),
);
}
}
This is the error
you are building widgets before id arrive check if the id is not null before build return, if the id is null return empty container e