_CastError (Null check operator used on a null value) from SQFLITE Flutter - flutter

I am trying to call this fetchall() method from totalprice() method, but every time it throws this error.
Here is my fetchall() method -
Future<List<CartModel>>? fetchall() async {
List<Map<String, Object?>>? map = await database?.query(tablename);
List<CartModel> cartproducts = [];
CartModel singleproduct = CartModel();
for (Map<String, Object?> i in map!) {
cartproducts.add(CartModel.fromJson(i));
singleproduct = CartModel.fromJson(i);
a = a + singleproduct.price!.toInt();
}
return cartproducts;
and this is the totalprice() method -
Future<int> totalprice() async {
int totalprice = 0;
List<CartModel>? products = await fetchall();
if (products != null) {
for (var i in products) {
totalprice = (totalprice + i.price!.toInt() * i.quantity!.toInt());
}
}
return totalprice;
Thanks for any little help.

Your line
List<Map<String, Object?>>? map = await database?.query(tablename);
Is probably assigning a null value to your map variable which your are later using with a null check operator ! which means that you are sure that it's not null, but the type List<Map<String, Object?>>? in the mentioned line gives it the ability to be null.
You can solve this by adding a null check before using the map variable like so
Future<List<CartModel>>? fetchall() async {
List<Map<String, Object?>>? map = await database?.query(tablename);
List<CartModel> cartproducts = [];
CartModel singleproduct = CartModel();
if(map != null)
for (Map<String, Object?> i in map!) {
cartproducts.add(CartModel.fromJson(i));
singleproduct = CartModel.fromJson(i);
a = a + singleproduct.price!.toInt();
}
}
return cartproducts;
}
Additional advice
For better code quality and readability, please follow variable naming conventions. For dart, make sure are your variables and methods are camelCase
so instead of fetchall => fetchAll
instead of cartproducts => cartProducts
instead of singleproduct => singleProduct
And so on...

Related

setter error in flutter while assigning value to class variable In flutter

I have created a demo where I am storing data in divide using sqfliteHelper and I want to create a object list to store data in memory for temporary use but I am getting error while assigning value to class variable, regarding setter required
here is my code
class SqfliteProvider {
List<CategoryModel> _categorylist = [];
List<CategoryModel> get categories {
return _categorylist;
}
static Future<List<CategoryModel>?> fetchcategory() async {
final db = await _getdb();
List<CategoryModel> templist = [];
List<Map<String, dynamic>> maplist = await db.query('categorytb');
if (maplist.isEmpty) return null;
templist = maplist.map((e) => CategoryModel.frommap(e)).toList();
//this statement showing an error ...required setter..
_categorylist = templist;
return templist;
}
}

for-loop should wait for future

I have a list of userIDs and I want to get a value from the database for each user and write it to a new list. But the for loop doesn't wait for the future and throws the error "Unhandled Exception: RangeError (index): Invalid value: Valid value range is empty: 0"
List userIDs = ["gsdgsgsgda32", "gwerszhgda7h", "fsdgz675ehds"];
Future <dynamic> getList() async {
List items=[];
for (var i = 0; i < userIDs.length; i++) {
items[i] = await getUserItems(userIDs[i]);
}
return items;
}
Future <String?> getUserItems(String? _userID) async {
String? userItem=" ";
final FirebaseApp testApp = Firebase.app();
final FirebaseDatabase database = FirebaseDatabase.instanceFor(app: testApp);
database.ref().child('users').child(_userID!).once().then((pdata) {
userItem = pdata.snapshot.child('item').value as String?;
});
return userItem;
}
This is not problem with future. List items is empty so when you call items[0] = 3; there is no items[0] and you get RangeError. Proper way to add element to list is call items.add(3)
So your code should look like this:
List userIDs = ["gsdgsgsgda32", "gwerszhgda7h", "fsdgz675ehds"];
Future <dynamic> getList() async {
List items=[];
for (var i = 0; i < userIDs.length; i++) {
final item = await getUserItems(userIDs[i]);
items.add(item);
}
return items;
}
Future <String?> getUserItems(String? _userID) async {
String? userItem=" ";
final FirebaseApp testApp = Firebase.app();
final FirebaseDatabase database = FirebaseDatabase.instanceFor(app: testApp);
database.ref().child('users').child(_userID!).once().then((pdata) {
userItem = pdata.snapshot.child('item').value as String?;
});
return userItem;
}
By using .then you are telling dart to continue running and come back when the Future completes.
Instead you should use await inside getUserItems.
You have to fiddle around a bit but here's a suggestion to start with:
Future <String?> getUserItems(String? _userID) async {
String? userItem=" ";
final FirebaseApp testApp = Firebase.app();
final FirebaseDatabase database = FirebaseDatabase.instanceFor(app: testApp);
userItem = (await database.ref().child('users').child(_userID!).once()).snapshot.child('item').value as String?
return userItem;
}
Also using String? for userItem and setting it to " " is a bit of an anti pattern. Since you allow it to be nullable i'd suggest having it as null writing your logic around that.
Try to use it like this
Future <dynamic> getList() async {
List items=[];
userIDs.forEach((item) async {
items.add(await getUserItems(item));
});
return items;
}

Flutter - await/async on a List - why does this only work when not using declarations?

Still new to Flutter :(. Can anyone help...
I have a class that stores a bunch of project information. One part of this is a list of topics (for push notification), which it grabs from a JSON file.
I apply a getter for the list of topics, and when getting it it calls an async function which will return a List
Future<List<String>> _pntopics() async{
final _json = await http.get(Uri.parse(_topicsUrl));
if (_json.statusCode == 200) {
return (jsonDecode(_json.body));
}else {
return [""];
}
}
Future<List<String>> get topics => _pntopics();
In my main.dart file, it calls this value like so...
Future<List<String>> _topiclist = await projectvalues.topics;
The response is however empty, pressumably because it is a Future - so it is grabbing the empty value before it is filled.
But I can't remove the "Future" part from the async method, because asnc methods require a Future definition.
Then I decided to remove the declarations entirely:
_pntopics() async{
final _json = await http.get(Uri.parse(_topicsUrl));
if (_json.statusCode == 200) {
return (jsonDecode(_json.body));
}else {
return [""];
}
}
get topics => _pntopics();
and in main.dart, a general declaration...
var _topiclist = await projectvalues.topics;
...and this works!
So what declaration should I actually be using for this to work? I'm happy to not use declarations but we're always to declare everthing.
You should return back Future<List<String>> return types to the function and the getter but for _topicslist you must use var, final or List<String> declaration because:
(await Future<T>) == T
i.e.
var _topiclist = await projectvalues.topics; // The type of _topiclist is List<String>
final _topiclist = await projectvalues.topics; // The type of _topiclist is List<String>
UPDATE
Your code should be:
Future<List<String>> _pntopics() async{
final _json = await http.get(Uri.parse(_topicsUrl));
if (_json.statusCode == 200) {
return List<String>.from(jsonDecode(_json.body));
}else {
return <String>[""];
}
}
Doing this you force _pnptopics returns List<String> as jsonDecode returns List<dynamic>.
P.S. It is good practice do not use dynamic types where they can be changed to specified types.

Flutter: Cannot store Firestore data to local variable (returns null)

I have an issue when trying to store data from Firestore to a local variable.
class AppUser {
String _userId;
Map<String, dynamic> _userData;
Future getUserDataFromDb() async {
_userData = await dbInterface.getFinancialsFromDB(_userId);
// dbInterface.getFinancialsFromDB(_userId).then((Map<String, dynamic> data) {
// _userData = data;
// });
print(_userData); // flutter: null
}
}
_userData always returns null.
class Db {
CollectionReference financials = FirebaseFirestore.instance.collection('financials');
Future<Map<String, dynamic>> getFinancialsFromDB(userId) async {
financials.doc(userId).get().then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
print(documentSnapshot.data()); // flutter: {'key1': 'data1', ...}
return documentSnapshot.data();
}
});
return null;
}
}
Db dbInterface = Db();
Within the "getFinancialsFromDB"-Function it prints the correct Map. So the issue isn't to retrieve the data from Firestore but to store it in the _userData variable.
The getUserDataFromDb() is called in an initState.
Any ideas what I could do to fix this issue? If you need any additional infos please let me know.
Thanks a lot, I really appreciate any help.
All the best,
Alex
When writing code an in async function, don't use then. Instead, use await to get the result of a Future.
Future<Map<String, dynamic>> getFinancialsFromDB(userId) async {
var documentSnapshot = await financials.doc(userId).get();
if (documentSnapshot.exists) {
return documentSnapshot.data();
}
else {
return null;
}
}

Is it possible to filter a List with a function that returns Future?

I have a list List<Item> list and a function Future<bool> myFilter(Item).
Is there a way to filter my list using the Future returning function myFilter()?
The idea is to be able to do something like this:
final result = list.where((item) => myFilter(item)).toList();
But this is not possible since where expects bool and not Future<bool>
Since the iteration involves async operation, you need to use a Future to perform the iteration.
final result = <Item>[];
await Future.forEach(list, (Item item) async {
if (await myFilter(item)) {
result.add(item);
}
});
You can iterate over your collection and asynchronously map your value to the nullable version of itself. In asyncMap method of Stream class you can call async methods and get an unwrapped Future value downstream.
final filteredList = await Stream.fromIterable(list).asyncMap((item) async {
if (await myFilter(item)) {
return item;
} else {
return null;
}
}).where((item) => item != null).toList()
You can try bellow:
1, Convert List => Stream:
example:
Stream.fromIterable([12, 23, 45, 40])
2, Create Future List with this function
Future<List<int>> whereAsync(Stream<int> stream) async {
List<int> results = [];
await for (var data in stream) {
bool valid = await myFilter(data);
if (valid) {
results.add(data);
}
}
return results;
}
Here's a complete solution to create a whereAsync() extension function using ideas from the accepted answer above. No need to convert to streams.
extension IterableExtension<E> on Iterable<E> {
Future<Iterable<E>> whereAsync(Future<bool> Function(E element) test) async {
final result = <E>[];
await Future.forEach(this, (E item) async {
if (await test(item)) {
result.add(item);
}
});
return result;
}
}
You can now use it in fluent-style on any iterable type. (Assume the function validate() is an async function defined elsewhere):
final validItems = await [1, 2, 3]
.map((i) => 'Test $i')
.whereAsync((s) async => await validate(s));
Try this:
final result = turnOffTime.map((item) {
if(myFilter(item)) {
return item;
}
}).toList();