Getting a document from Firestore results in "The method 'data' was called on null. Receiver: null Tried calling: data())" - flutter

I am new to Flutter and trying to get a document from a collection; there is no error in the code but, still, the document is not obtained.
I am trying to return a variable having String in the method _onPressed() but I'm stuck at that point.
Future _onPressed() async{
var msg;
await db.collection('Messages').doc(widget.brew.id).get().then((value){
print(value.data()['Message']);
return value.data()['Message'];
});
msg = msg.data()['Message'];
return msg;
}

Wrong assignment done here. change the above code
Future _onPressed() async{
var docSnap = await db.collection('Messages').doc(widget.brew.id).get();
if (docSnap.exists) {
print('Document data: ${documentSnapshot.data()}');
return docSnap.data()['Message'];
} else {
print('Document does not exist on the database');
return docSnap.data()['Message'];
}
}
In current snippet, msg.data() throws the err as the msg was null at that time.

Related

Unhandled Exception: type 'Null' is not a subtype of type 'ApiResponse<Map<String, dynamic>>'

I'm getting the following error while fetching data from server but I know this error is not about how I'm fetching data. It is related to the null safety which was added in latest flutter update. I'm not so much familier with it.
Here is the Errors
enter image description here
I tried to check if there was something wrong on the line highlighted and for me it was ok.
Here is the code of servers_http.dart:
ApiResponse<Map<String, dynamic>> resp = await get<Map<String, dynamic>>("detail/random");
if (resp.success ?? false) {
return StarConfig.fromJson(resp.data!);
}
return null;
}```
**and this stars_provider.dart**
```///Initialize engine and load last server
void initialize(BuildContext context) {
engine = OpenStar(onStarStageChanged: onStarStageChanged, onStarStatusChanged: onStarStatusChanged)
..initialize(
lastStatus: onStarStatusChanged,
lastStage: (stage) => onStarStageChanged(stage, stage.name),
groupIdentifier: groupIdentifier,
localizedDescription: localizationDescription,
providerBundleIdentifier: providerBundleIdentifier,
);
Preferences.instance().then((value) async {
starConfig = value.getServer() ?? await ServersHttp(context).random();
notifyListeners();
});
}```
what I need to change?
Slution 1:
my understanding that you are requesting data from the server using
ApiResponse<Map<String, dynamic>> resp = await get<Map<String, dynamic>>("detail/random");
if so all you need to do is to change it to :
ApiResponse<Map<String, dynamic>>? resp = await get<Map<String, dynamic>>("detail/random");
if (resp?.success ?? false) {
return StarConfig.fromJson(resp.data!);
}
Slution 2:
i believe this function is the problem and starConfig doesn't accept null and base on your code :
Preferences.instance().then((value) async {
starConfig = value.getServer() ?? await ServersHttp(context).random();
notifyListeners();
});
this part is returning null when his only job is to return ApiResponse<Map<String, dynamic>>
await ServersHttp(context).random()
now this i believe this will work if you
Preferences.instance().then((value) async {
ApiResponse<Map<String, dynamic>> test;
starConfig = value.getServer() ?? test.fromJson({});
notifyListeners();
});
Note : i don't know what ServersHttp(context).random() do.

getting an error on transaction function on flutter platform

I am writing a transaction function to add coins in database but I am getting error. The code where error is coming is highlighted in image
The error is : The argument type 'Set' can't be assigned to the parameter type 'Map<String, dynamic>'
// function to add coin v.i.a transaction method
Future<bool> addCoin(String id, String amount) async {
try {
String uid = FirebaseAuth.instance.currentUser!.uid;
var value = double.parse(amount);
// these documents are downloaded when you create a stream
DocumentReference documentReference = FirebaseFirestore.instance
.collection("users")
.doc(uid)
.collection("coins")
.doc(id);
FirebaseFirestore.instance.runTransaction((transaction) async {
DocumentSnapshot snapshot = await transaction.get(documentReference);
if (!snapshot.exists) {
documentReference.set({'Amount': value});
return true;
}
double newAmount = snapshot['Amount'].data() + value;
transaction.update(documentReference,{'Amount' = newAmount });
return true;
});
return true;
} catch (e) {
return false;
}
}
The line where error is coming is highlighted
just replace = with : to change the argument from Set to Map:
transaction.update(documentReference,{'Amount' : newAmount });

Flutter future return type issue with async functions

I have a weird error with my Flutter code involving a Future<T> return type. I have a fairly simple piece of code that makes a get request to the backend, and a .then clause to handle the return. Everything's fine, and as soon as I add onError to handle possible back error (namely 403/404 errors), I have an issue regarding the return type, quoting that Future<dynamic> can't be returned when I expect a Future<String?>, and that's in spite of onError always returning null.
Any idea how I can fix that behavior? Thanks in advance !
Code:
Future<String?> getUserStatus(String id) async {
return requestManager.get("/users/$id/status")
.then((response) {
final dynamic userStatus =
(response as Map<String, dynamic>)["status"];
if (unsubStatus == null) {
return Future.value();
}
return Future.value(userStatus.toString());
}, onError: (error) {
print("An error occured when reading response : $error");
return null;
}).onError((error, stackTrace) => Future.value("NoStatus")); // I also tried to return null
}
Error:
A value of type 'Future<dynamic>' can't be returned from an async function with return type 'Future<String?>'.
- 'Future' is from 'dart:async'.
}).onError((error, stackTrace) => Future.value("NoStatus"));
I recommended using try bloc and await instead of using then and onError:
Future<String?> getUserStatus(String id) async {
try {
var response = await requestManager.get("/users/$id/status");
final dynamic unsubStatus = (response as Map<String, dynamic>)["status"];
if (unsubStatus == null) {
return null;
} else {
return unsubStatus.toString();
}
} catch (e) {
print("An error occured when reading response : $e");
return null;
}
}
Future<String?> getUserStatus(String id) async {
final result =await requestManager.get("/users/$id/status");
final dynamic userStatus = (response as Map<String, dynamic>)["status"];
if (unsubStatus == null) {
return Future.value();
}
return Future.value(userStatus.toString());
}

Flutter: I still get the error "Null check operator used on a null value" on the value I made Nullable

static Database? _db;
if (_db != null) {
return;
}
try {
String _path = await getDatabasesPath() + 'users.db';
_db =
await openDatabase(_path, version: _version, onCreate: (db, version) {
print("Database oluşturuldu");
});
} catch (e) {
print(e);
}
}
static Future<List<Map<String, dynamic>>> query() async {
print("query");
return await _db!.query(_tableName);
}
I get the error Null check operator used on a null value even though I made the _db value nullable.
Appreciate if someone can advise. Thank you in advance!
Nullable simply means that a variable can have a nullvalue. With the ! you assume that the variable is not null at this point and therefore you can call the method. But of course if you don't have a value assigned in your object now, then it will try to call the method on null value.
Initialize somewhere in the code your database object before you try to make a query.
You can return empty list or fetch again on null case, use ! only when you are certain the value is not null. It would be better to do a null check 1st.
static Future<List<Map<String, dynamic>>> query() async {
print("query");
final result = await _db?.query(_tableName);
if (result == null) {
print("got null db"); // you can reinitialize the db
return [];
} else {
return result;
}
}
static Database? _db;
//database was never initialized, null by default in this instance
static Future<List<Map<String, dynamic>>> query() async {
print("query");
//you attempt to get the value from a null object while casting it as non null
return await _db!.query(_tableName);
}
You have to initialize a null value before using the notation (!) on it else you're casting a null object as non-null. To avoid any errors, rewrite it as
return (await _db?.query(_tableName)) ?? [];
this will fail but no nullpointer exception will be thrown

Dart return Future.value is always null

I am trying to build a URL from a Firebase Storage file but the Future<String> I have built always seems to return null. This is the Future I am calling:
Future<String> getUrlFromStorageRefFromDocumentRef(
DocumentReference docRef) async {
try {
docRef.get().then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
String filename = documentSnapshot.get('file');
firebase_storage.Reference ref = firebase_storage
.FirebaseStorage.instance
.ref()
.child('/flamelink/media/$filename');
if (ref == null) {
return Future.error("Storage Reference is null");
} else {
print(ref.fullPath);
return Future.value(
'https://storage.googleapis.com/xxxxxxxxx.appspot.com/${ref.fullPath}');
}
} else {
return Future.error('No Snapshot for DocumentReference ${docRef.id}');
}
});
} catch (e) {
print(e);
return Future.error('No DocumentReference for ID ${docRef.id}');
}
}
The line in question is :
return Future.value(
'https://storage.googleapis.com/xxxxxxxxx.appspot.com/${ref.fullPath}');
It's worth noting that the String is generated from the Firebase Storage path and everything looks perfect until it comes to return the value.
It should return the String value back to my calling code which at the moment looks like this:
DocButtonCallback docCallback = () async {
bool isKidsDoc = item.screenId == StringsManager.instance.screenIdKids;
try {
// first we need to get the URL for the document ...
var url = await AssetManager.instance
.getUrlFromStorageRefFromDocumentRef(isKidsDoc
? feature.relatedDocumentKidsRef
: feature.relatedDocumentRef);
String urlString = url.toString();
canLaunch(urlString).then((value) {
launch(urlString);
}).catchError((error) {
// TODO: open alert to tell user
});
} catch (error) {
print(error);
}
};
I have tried many different ways to get that String including:
DocButtonCallback docCallback = () async {
bool isKidsDoc = item.screenId == StringsManager.instance.screenIdKids;
await AssetManager.instance
.getUrlFromStorageRefFromDocumentRef(isKidsDoc
? feature.relatedDocumentKidsRef
: feature.relatedDocumentRef)
.then((urlString) {
canLaunch(urlString).then((value) {
launch(urlString);
}).catchError((error) {
// TODO: open alert to tell user
});
}).catchError((error) {
// TODO: open alert to tell user
});
};
For some reason, the Future always returns null. What am I doing wrong here?
You are returning the Future value inside the then() callback, which essentially returns this value from the callback itself rather than from your getUrlFromStorageRefFromDocumentRef() function. There you should only need to add a return statement before that:
Current:
docRef.get().then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
...
After:
/// Adding the return statement here to return the actual value
/// returned internally by the then callback
return docRef.get().then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
...
If you hover over the then() callback, your IDE should show you that this callback will return Future<T> (or whatever generic type placeholder) which need to be returned as well in order to make it available