Error while using Flutter with Riverpod and null safety - flutter

I am using Flutter with Riverpod and null safety for the first time and I have the following provider that should return ImageProfile or null.
final myProfileImageProvider = Provider.autoDispose.family<ProfileImage?, int>(
(ref, index) {
final images = ref.watch(editMyProfileViewModelProvider.state).images;
if (index < images.length) {
return images[index];
}
return null;
},
name: 'myProfileImageProvider',
);
I am reading the provider inside a function like this:
final profileImage = context.read<ProfileImage>(myProfileImageProvider(profileImageIndex));
But I am getting the following compiler error.
The argument type 'AutoDisposeProvider<ProfileImage?>' can't be assigned to the parameter
type 'ProviderBase<Object, ProfileImage?>' because 'ProfileImage?' is nullable and 'Object'
isn't.
Notice that inside a function, I can't use watch or useProvider. I must use context.read. Please note that useProvider() does solve the problem but can't use it inside a function. The problem is when reading the provider inside a function.
Any body out there know the answer to this?
I appreciate any help.
Thanks

Related

Can't assign non-nullable type to a nullable one

error: The argument type 'Future<List<GalleryPictureInfo>>' can't be assigned to the parameter type 'Future<List<GalleryPictureInfo>>?'.
Is this Dart Analysis or me? The project still compiles.
Upd. Added code example
FutureBuilder<List<GalleryPictureInfo>>(
future: derpiService.getListOfImages(),
//other code
);
#override
Future<List<GalleryPictureInfo>> getListOfImages(arguments) async {
List<GalleryPictureInfo> listOfImages = [];
var searchImages = await getSearchImages(tags: tags, page: page);
//adding images to List
return listOfImages;
}
It's something with FutureBuilder actually. I should've mention this.
Upd. "Fixed" with // ignore: argument_type_not_assignable
Looks like a problem with Dart Analysis for now
Upd. Error
It actually is an error which is pretty self explanatory.
The acutal error comes because of null safety in dart.
For ex:
void main(){
var number = getNumber(true);
int parsedNumber = int.parse(number);
print(parsedNumber);
}
String? getNumber(boolean value) {
if (value){
return null;
} else return "1";
}
So here, getNumber function either returns null or "1" depending upon the value of value variable. So, number variable's type is String?.
But the error shall arise in the next line when you try to call int.parse(). int.parse function takes an argument which should be a String but the value passed in the function is of type String?. So if we pass null in int.parse it shall throw an error.
That's why Dart analysis makes it easier to identify such cases by telling us that the value can be null and it might throw.
However the code depends upon your actual code of your project. It says that you are passing Future<List<GalleryPictureInfo>>? which is of nullable type to a function which requires Future<List<GalleryPictureInfo>>. So, before passing the value you might want to check if the value you are passing is not null.
If you are sure that the value can never be null then if for ex: if you are passing a variable called value, you might wanna try someFunctionWhereYouPassValue(value!)
That ! means that you are sure that the value will never be null.
For more details about null safety you can see:
https://dart.dev/null-safety/understanding-null-safety

Warning implementing list filtering in Flutter

I have the following code to filter a list from data to be shown in a listView:
child: FutureBuilder(
future: fetchPacientes('todo'),
builder: (context, snapshot) {
if (snapshot.hasData) {
var filteredList = snapshot.data;
print("a minusculas:" +
_controller.text.toLowerCase());
filteredList = filteredList
.where((element) => (element.nombre
.toLowerCase()
.contains(
_controller.text.toLowerCase()) ||
element.NHC.toLowerCase().contains(
_controller.text.toLowerCase()) ||
element.apellidos.toLowerCase().contains(
_controller.text.toLowerCase())))
.toList();
But I am getting an error at point:
.where(...
This is the error output:
The method 'where' can't be unconditionally invoked because the receiver can be 'null'.
I am trying to migrate an old app to Null Safety, but I am not able to solve this issue. The proposed solution is to add a null check at filteredList! but the error is not removed when doing that way
That error means that the object on which the . is applied (in this case, the filteredList) can be null, so it would throw an exception if filteredList will be actually null.
So, to avoid the error, you have these options:
Add a ! after filteredList: in this case, you're assuring the compiler that filteredList will never ever be null, and the error will disappear. Note that this doesn't actually prevent it from being null: you're just reassuring the compiler about it, and filteredList could still be null. In that case, the app will throw a dedicated exception telling you that it found a 'null' object when you declared in the code that this should not have happened
Check if filteredList is null: add a few lines of code testing if it is really null, and then handle the case, even something basic like returning a Text('filteredList is empty'). After this, you can safely write filteredList! because you are sure that it will never be null, since you actually tested id.
Set a default value for filteredList in case it's null: Dart has this operator that assigns a value to an object if it is null: filteredList ??= []. Again, after using this, you can safely write filteredList! because it will never be null.
PS sorry, didn't notice the last sentence. Since adding ! and a null check isn't working, I'd try setting a default value for filteredList. Or maybe checking for null on snapshot.data, and then set an explicit non-nullable type for filteredList, like List<Object> filteredList.
The error is becausesnapshot.data can be null. Try adding a ? before your .where like so :
filteredList = filteredList?.where(...);

Unhandled Exception: type 'List<Widget>' is not a subtype of type 'Iterable<MyWidget>' in type cast

After migrating to null safety, the migration tool added as Iterable<SetWidget> to my code. But unfortunately i get this error:
Unhandled Exception: type 'List<Widget>' is not a subtype of type 'Iterable<SetWidget>' in type cast
This is the code:
final List<Widget> _sets = [];
Map getSets() {
Map sets = {};
int k = 0;
for (SetWidget set in _sets as Iterable<SetWidget>) {
sets.putIfAbsent(k.toString(), () => set.getMap());
k++;
}
return sets;
}
What is the issue here?
I don't know why the tool decided to do that, but if you think about it, it obviously throws an error. _sets is a list of Widgets, which means it could include for example a Column, a Container, and a SetWidget, so it can't be cast to a SetWidget iterable.
is getMap() a method in the SetWidget class? if it is, could you change the List<Widget> to a List<SetWidget> and remove the as Iterable<SetWidget>? Hopefully, that solves your problem.
Also, side note, what is this code for? Are you turning a list into a Map<String, Function> where the string is just an index? if you are, why not use a list instead?
for (SetWidget widget in _sets)
{
sets.add(widget.getMap)
}

Migrating from Provider to Riverpod

I am stuck using Provider and came across Riverpod which is just the next gen of Provider. I am trying to create a StreamProvider using Riverpod but I am getting an error.
Here is the code for creating the StreamProvider:
final trxnStreamProvider = StreamProvider.autoDispose<List<Trxns>>((ref) {
final stream = firestoreService.getAgencyTrxns();
return stream.map((snapshot) => snapshot.docs.map((doc) => Trxns.fromFirestore(doc.data)).toList());
});
The error I get marks the code "doc.data". Here is the error text:
The argument type 'Object? Function()' can't be assigned to the parameter type 'Map<String, dynamic>'.
Here is the code for "Trxns.fromFirestore(doc.data)":
Trxns.fromFirestore(Map<String, dynamic> firestore)
: clientFName = firestore['clientFName'],
clientLName = firestore['clientLName'];
I'm still new to this and am having a hard time understanding the error message. Is it saying that "doc.data" is not the right type? If so, how do I fix this? If not, what is wrong and how do I fix it?
Map<String, dynamic> data() => dartify(jsObject.data());
data is a method so you need to call it:
doc.data()
doc.data mean you want to pass a function

Flutter-Riverpod - how to combine providers to filter on a Stream

I'm trying to follow the example docs on how to combine Providers using Flutter & Riverpod to filter a list of items. The data is coming from Firestore using Streams:
final carListProvider = StreamProvider.autoDispose<List<Car>>((ref) {
final carsRepo = ref.watch(carsRepositoryProvider);
return carsRepo.cars();
});
This all works fine and I can render the list of cars no problem. Now I want to give the user the option to filter the list based on color:
enum CarColorFilter {
all,
red,
white,
black,
}
final carListFilter = StateProvider((_) => CarListFilter.all);
And then following the docs example, my attempt to combine the providers:
final filteredCars = StreamProvider<List<Car>>((ref) {
final filter = ref.watch(carListFilter);
final cars = ref.watch(carListProvider); <-- This line throws the error
switch (filter.state) {
case CarColorFilter.all:
return cars;
case CarColorFilter.red:
return cars.where(...)
default:
}
})
On the line declaring the 'cars' variable the editor complains:
The argument type 'AutoDisposeStreamProvider<List>' can't be
assigned to the parameter type 'AlwaysAliveProviderBase<Object,
dynamic>'
I think the difference between my use case and the docs is that in the example given the List<Todo> is a StateNotifierProvider whereas in my case the List<Car> is a StreamProvider. Any help would be much appreciated.
Found the answer in the docs, posting here in case it helps anyone else:
When using .autoDispose, you may find yourself in a situation where
your application does not compile with an error similar to:
The argument type 'AutoDisposeProvider' can't be assigned to the
parameter type 'AlwaysAliveProviderBase'
Don't worry! This error is voluntary. It happens because you most
likely have a bug:
You tried to listen to a provider marked with .autoDispose in a
provider that is not marked with .autoDispose
Marking the filteredList provider as autoDispose resolves the issue.