Flutter Firebase DocumentReference.set() is not completing - firebase

My application was writing to Firestore but suddenly stopped working. When I try to write to Firestore my write method does not complete. I have made the following simple test method to troubleshoot my problem but can't seem to figure out what is going on:
//In database.dart
Future<void> testSet() async {
final reference = FirebaseFirestore.instance.doc('users/test');
await reference.set({'TEST': 'Value'});
print('This is never printing');
}
//In home_page.dart called via clicking a button
Future<void> _testSet(context) async {
final database = Provider.of<Database>(context, listen: false);
await database.testSet();
}
I have tried emptying my Firestore Database as well as adding a users collection; however nothing has worked. Why am I unable to write to Firestore?

Related

Shared Preferences not working when using FCM backgroundHandler

I am working on this Flutter app and I have implemented Firebase Cloud Messaging. I added the following code to make sure I can use the Shared Preferences package. It seems to work, but the functionality does not work correctly.
Extra configuration code
if (Platform.isAndroid) SharedPreferencesAndroid.registerWith();
if (Platform.isIOS) SharedPreferencesIOS.registerWith();
The backgroundhandler in action
Future<void> backgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
if (Platform.isAndroid) SharedPreferencesAndroid.registerWith();
if (Platform.isIOS) SharedPreferencesIOS.registerWith();
print("App is in background: Message received ");
final prefs = await SharedPreferences.getInstance();
final listOfTopics = prefs.getStringList('out_of_stock_topics') ?? [];
String topic = 'default_topic';
if (listOfTopics.contains(topic)) {
listOfTopics.remove(topic);
await prefs.setStringList('out_of_stock_topics', listOfTopics);
}
}
The code above deletes the topic in the list. Then the list is set with prefs.setStringList. I checked, and the code goes into the if statement. It removes the item from the list. But something goes wrong in prefs.setStringList I suppose.
Because later I use the following code to check the items in the 'out_of_stock_topics' list.
Code to check list of topics
final prefs = await SharedPreferences.getInstance();
final listOfTopics =
prefs.getStringList('out_of_stock_topics') ?? [];
print(listOfTopics);
But the topic is not correctly deleted and is still there. I think there is something wrong in the backend of the backgroundhandler. I tested this feature with 2 buttons: "add topic" and "delete topic". And with those separate buttons it does delete the item from the 'out_of_stock_topics' list.
Does anyone know how to fix this problem?
Thanks!

flutter firstWhere not responding (firestore)

I did a function a few months ago where my application is waiting for the user documents and responding accordingly. It was working like a charm until I optimized and updated the project to the last version.
If there is a user document, the stream yields the document and closes the stream.
If there is no user data in the cloud firestore, the stream yields null and awaits for the document to appear in the cloud.
// this function doesn't work properly and it should work but `firstWhere` is not
// listening to the stream unless there is a listener already which makes no sense
static Stream<DocumentSnapshot> get getUserDocumentWhenExists async* {
User user = FirebaseAuth.instance.currentUser;
if (user == null) throw 'No user is signed in';
FirebaseFirestore firebase = FirebaseFirestore.instance;
CollectionReference usersCollection = firebase.collection('users');
Stream<DocumentSnapshot> userDocumentStream = usersCollection.doc(user.uid).snapshots();
userDocumentStream.listen((event) {}); // <= this is here for the code to work
DocumentSnapshot userDocument = await userDocumentStream.first;
if (userDocument.exists == false) {
yield null;
yield await userDocumentStream.firstWhere((userDocument) {
// not beeing called without a previous listener
return userDocument.exists;
});
} else {
yield userDocument;
}
}
If you run this code without removing userDocumentStream.listen((event) {}) it will work without a problem as it did before the update.
My questions are:
Is this a bug?
Why is this happening? or did I just wrote something wrong?
Edit: I made a custom test without firebase and everything works fine. Just in this particular case firstWhere() is not listening to the stream
Edit2: after some more testing I discovered that any listener after userDocumentStream.first will not work. Now I'm more confused and I really need some help
I think after first() is called, the subscription is canceled even if in the first documentation it says otherwise:
"Internally the method cancels its subscription after the first element. This means that single-subscription (non-broadcast) streams are closed and cannot be reused after a call to this getter."
My solution:
Create a snapshots() stream for the first() and one for firstWhere()
final documentReference = usersCollection.doc(user.uid);
final userDocument = await documentReference.snapshots().first;
if (userDocument.exists == false) {
yield null;
yield await documentReference.snapshots().firstWhere((userDocument) {
return userDocument.exists;
});
} else {
yield userDocument;
}

How to listen firebase updates in real time in Flutter

I have a stream which read user data from firebase. I trigger it after signin, it works perfectly. I show the data in my appbar. When I update firebase manually, I want to see the new date instantly on my appbar. First, I guessed there is something wrong with my appbar but then I noticed that my stream do not triggered when I update firebase data. Here is my stream code snippet. What am I missing?
static Future<User> userDataStream(userID) async {
print("userDataStream");
final databaseReference = Firestore.instance;
User currentUser = User();
await for (var snapshot in databaseReference
.collection('users')
.where('userID', isEqualTo: userID)
.snapshots()) {
currentUser.userName = snapshot.documents.first.data['userName'];
currentUser.email = snapshot.documents.first.data['email'];
currentUser.userID = snapshot.documents.first.data['userID'];
currentUser.level = snapshot.documents.first.data['level'];
currentUser.balance = snapshot.documents.first.data['balance'];
print(currentUser.balance);
return currentUser;
}
return currentUser;
}
How you are using this stream matters. await for starts listening to the user, then you do return currentUser; in it and break the await for. Therefore, it cannot keep listening to the stream in the future.
Instead of the return currentUser; inside await for, you can do something like setState((){this.renderedUser = currentUser;}) so that the user that comes from the server becomes the rendered one. If you do that, also add if (!mounted) return; inside the await for so that you stop listening to it when you realize you are in a different screen.
A better alternative may be to use the StreamBuilder widget.
If you run your current code, and make a change to the database, the print statement should be run again. That's because the snapshots is already listening for changes to the database, and calling your code when those happens.
The problem is that you return a Future<User> and a future can only be resolved (get a value) once. If you want to return live data that'd be a Stream<User> (and typically a StreamBuilder instead of a FutureBuilder to build a UI from it).

How to delete a subcollection from firestore flutter

so am new using firestore to store data. at the moment i need to delete data already saved in the Firestore through my App. I have tried
Future<void> removeDocument(String id, String userId){
return ref.document(userId).collection(userId).document(id).delete().whenComplete((){
print("DELETE DONE::");
});
}
But its not working.
The thing is I used the userId to save the user details
now I want to delete the data but it does not delete the data even though the print message shows in my Log.
The method below is how i add data to the Firestore
Future<void> addDocument(Map data, String userId){
return ref.document(userId).collection(userId).add(data);
}
void setupLocatorWorkout() {
locatorWorkout.registerLazySingleton(() => Api('workout_goal'));
locatorWorkout.registerLazySingleton(() => CRUDRemoteDataSource());
}
Api(this.path){
print("$path");
ref = _db.collection(path); // this is the base collection
}
please what am i doing wrong here?
Thank you!!!
Delete a User by UID:
void deleteUser(User user) async {
await db.collection(COLLECTION_NAME)
.document(user.uid)
.delete()
.then((_) {
print('User deleted.');
});
}
Don't forget to add import 'dart:async'; at the top
The answer is you shouldn't.
According to the Firestore docs, you should not do this because:
While it is possible to delete a collection from a mobile/web client, doing so has negative security and performance implications.
However the link shows how it can be done frome some platforms.

Flutter cloud firestore not updating automatically

I try to read listen to a stream from Firebase with this code:
visibleListsIds.forEach((final String listId) async {
final Stream<List<WishList>> wishListStream = sharedCollection()
.document(listId)
.snapshots()
.map((DocumentSnapshot documentSnapshot) {
log.d("updated Document Snapshot: ${documentSnapshot.data}");
return [
_getSerializers()
.deserializeWith(WishList.serializer, documentSnapshot.data)
];
});
wishListStreams.add(wishListStream);
});
Where sharedCollection() gives me access to the Firestore instance with the correct collection
I try to write to the collection, with this code
DocumentReference postRef = sharedCollection().document(wishList.listId);
firestore.runTransaction((Transaction tx) async {
DocumentSnapshot postSnapshot = await tx.get(postRef);
if (postSnapshot.exists) {
await tx.update(postRef,
_getSerializers().serializeWith(WishList.serializer, wishList));
} else {
await tx.set(postRef,
_getSerializers().serializeWith(WishList.serializer, wishList));
}
});
What happens:
I can write to Firebase but only one change at a time. When I do the next update, the last one gets reverted.
I can see the updated data only in the Firebase Console. The App does not show it and it does not show in the log at log.d("updated Document Snapshot: ${documentSnapshot.data}");.
When I modify data in the Firebase Console, I can also not see it change
BUT once I reload the App, all the Data syncs up to the current state of the Firebase Console
Anyone know why I do not get updates with the Stream?
Thanks for your help.
I use the Cloud Firestore Plugin:
cloud_firestore: ^0.13.0+1

Resources