How to deal with information that arrives null? - NoSuchMethodError - flutter

I'm getting null information from a web api. If a single information is null, the error will occur:
Error: Exception: NoSuchMethodError: '[]'
Dynamic call of null.
Receiver: null
Arguments: ["address"]
I declared this information in the model like this:
final String? address;
..
address: json['data1']['data2'][0]['data3']['address'][0]
I tried to do something like:
address: json['data1']['data2'][0]['data3']['address'][0].isEmpty
? ''
: json['data1']['data2'][0]['data3']['address'][0],
But it does not work.
I appreciate if anyone can help me analyze it!

The only thing you can do is to anticipate the null values and handle each case as needed.
For instance, if a null value is not accepted at all, you could wrap the code in throw ... catch statement then throw an error -- e.g.Missing Data and handle that error.
If having a null value is fine, you can use the null aware operator ? (or a nested if-statements if you prefer that). For example, assuming the value is a String, you could do something like this:
final String? myValue = json['data1']?['data2']?[0]?['data3']?['address']?[0];
Though, keep in mind if you're accessing a list by index, you still can get a RangeError if the index is out of range or if the list is empty. In such case you may need to split the process in a separate method and inspect each part separately such as:
String? extractValue(Map<String, dynamic> json) {
final firstList = json['data1']?['data2'];
if (firstList is List && firstList.isNotEmpty) {
final innerList = firstList[0]['data3']?['address'];
if (innerList is List && innerList.isNotEmpty) {
return innerList[0];
}
}
return null; // or return a default value or throw an error
}

You can handle such arguments ( arguments that give you null value) like this.
Let's say there's a variable a and there's a possibility that it'll give a null value, you can give it a default value.
For example:
There is a variable 'a', which is your data source.
String name = a ?? "This is not a null value";
The ?? would check if the value is null or not. If it's null, it would assign the value that you provided, otherwise it would keep the existing one.

Related

In dart what is the difference between ? and ! for nullable types?

I am new to Dart and Flutter.
In dart what is the difference between using ? and ! for null-able types?
validator: ((value) {
if (value?.isEmpty) {
return "Field is required";
}
return null;
}),
validator: ((value) {
if (value!.isEmpty) {
return "Field is required";
}
return null;
}),
Thanks in advance!
Good topic about it : What is Null Safety in Dart?
But in short, you use "?" when you want to allow the value to be null and use it accordingly, like this:
String? test;
if (test?.isEmpty == true) { // And is not null, but you don't need to check it
// If null, will never pass there but without error
}
And use "!" when you want to be sure to have a non nullable value, like this:
String? test;
if (test!.isEmpty == true) { // Will throw an error
...
}
the difference between the two,one can be null initially, but the other cannot.
I hope you understand in the example below.
To specify if the variable can be null, then you can use the nullable type ?
operator, Lets see an example:
String? carName; // initialized to null by default
int? value = 36; // initialized to non-null
value = null; // can be re-assigned to null
Note: You don’t need to initialize a nullable variable before using it. It is initialized to null by default.
The Assertion Operator (!)
Use the null assertion operator ( ! ) to make Dart treat a nullable expression as non-nullable if you’re certain it isn’t null.
int? someValue = 30;
int data = someValue!; // This is valid as value is non-nullable
In the above example, we are telling Dart that the variable someValue is null, and it is safe to assign it to a non-nullable variable i.e. data
I hope you understand????
As for your example;
if you notice, the validator {String? value} value can initially be null. but the only difference between both works in the code you wrote will be the running cost. '?' it will cost some time when you define it again. because it is already stated in the function that it will be null as a start.
It's a good question and the answer is here as a person.
'?' it means it will get value later or it can be null( initially or at any instance) for example
String? carName;
'!' it means you are going to receive the value and it can not be null. it will check the value if the value is null it will give exception.
have a look on example for clear difference:
List? blocks;
...
// you are not sure blocks variable is initialized or not.
// block is nullable.
final Block? block = blocks?.first;
// you are sure blocks variable is initialized.
// block is not nullable.
final Block block = blocks!.first;
hope you got it if yes accept the answer or comment me if you have question

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

I get an error with snapshot.data()["~~~"] flutter

I'm trying to get the value from Firestore with the following code. But I'm sorry I got this error. Help me
DocumentSnapshot snapshot = await FirebaseFirestore.instance.collection("users").doc(user.uid).get();
print(snapshot.data()["location"] as String);
Details of the error
The method '[]' can't be unconditionally invoked because the receiver can be 'null'. Try making the call conditional (using '?.') or adding a null check to the target ('!').
I tried various things, for example print(snapshot.data()!['location'] as String);
error code
The operator '[]' isn't defined for the type 'Object'. Try defining the operator '[]'.```
The method '[]' can't be unconditionally invoked because the receiver can be 'null'. Try making the call conditional (using '?.') or adding a null check to the target ('!').
As you might be able to guess, you are getting an error because if the snapshot has no data, it will return null, which will error. Here are some ways of fixing it:
adding a bang operator (!) (But you say this did not fix the issue?)
print(snapshot.data()!['location'] as String);
note the ! after data(), the bang operator tells dart to ignore a nullable value, this code will work as long as snapshot.data() is not null, of course, this is not safe, because snapshot.data() could be null, so here is an obvious solution:
var data = snapshot.data();
if (data != null) {
print(data!['location'] as String);
}
this should work, because now if data is null, the print statement will simply not run.
adding a ? operator
print(snapshot?['location']);
note the ? after data(), the ? operator will escalate a null value, so if snapshot.data() is not null, snapshot.data()?['location'] will be equal to snapshot.data()['location'], but if snapshot.data() is null, snapshot.data()?['location'] will be equal to null instead of throwing an error.
Adding a ?? operator
print(snapshot.data()?['location'] ?? 'the value was null');
Here, it is necessary to use both the ? operator to escalate the null value and the ?? operator.
The ?? operator will output the value on the left if the value is not null and will output the value on the right if the value on the left is null, so in this case, if snapshot.data() is null, that will escalate the null value, meaning snapshot.data()?['location'] will be null, which in turn means that instead of printing 'null', the ?? operator will print 'the value was null'
So to conclude, if you are sure the value is not null, you can use the bang operator !, if you are not sure, then you can use a combination of ? and ?? to your advantage.
Edit
It looks like adding one of the above solutions still won't fix the issue, here is an updated version that will hopefully fix the new issues?
print((snapshot.data()! as Map<String, dynamic>)['location'] as String);
you need to add null check operator to make sure that receiver is not null.
print(snapshot.data()!["location"] as String);

How to use the Null assertion operator with instance fields

I'm having trouble understanding how to type promote an object's field if it is nullable. Let's say I had the following Comment class and tried to access its one nullable field:
class Comment {
final String? text;
Comment(this.text);
}
void main() {
final comment = Comment("comment");
if (comment.text!= null) {
String text = comment!.text;
}
}
The Dart compiler would give me an error for trying to assign a nullable variable to a non-nullable variable. From what I've gathered from looking into this topic, it's impossible to have type promotion with instance variables because instance variables can be modified which can then break the sound null-safety. I've seen the Null assertion operator (!.) being used in these circumstances, however it doesn't seem to work with fields, only with methods.
With dart null-safety, how should I go about assigning a nullable field such as String? to a non-nullable variable (String). To the same effect, how should I go about passing a nullable field to a function that requires a non-null argument.
You can fix it in different ways:
Use local variable (recommended)
final local = comment.text; // <-- Local variable
if (local != null) {
String text = local;
}
Use ?. and provide a default value
String text = comment?.text ?? 'Default value';
Use Bang operator !
if (comment.text != null) {
String text = comment.text!; // <-- Bang operator
}
Note: Bang operator can result in a runtime error if the text was null.

Should you check runTimeType of variables in fromJson functions as best practice?

Pretty basic question, but wondering what the best practice is and can't seem to find any references to this on SO or elsewhere.
Should you check the runTimeType of properties before you attempt to store them when you parse fromJson even if you are confident it should never be anything but the type you think, or null? Or do we just accept the error if this highly unlikely event ever happens?
Thanks !
factory SomeClass.fromJson(Map data) {
if (data == null) return null;
String someString = data['someString']; //no runTimeType check
int someInt = data['someInt']; //no runTimeType check
try {
assert(someString != null, 'Some String was null in Some Class Json');
assert(someInt != null,
'Some Int null in Some Class Json');
} catch (e) {
return null;
}
return SomeClass(someString: someString, someInt: someInt);
}
It will be really nice to check the runtime type of the variable as well, as it will prevent any potential app crash when the database is updated in the future.
As far as the null checks are concerned, I personally pass in a default value like for String I store an empty string as the default value instead of null.
String someString = data['someString'] ?? '';
Even if the database returns a null value, our app should be able to handle those conditions.
The most common type of error that I've personally experienced is during the parsing of data. Type String is not a subtype of int. Something like that. So, I guess it would be nice to check the runtime types of values returned from the backend.