I'm trying to migrate an existing, small Flutter app to Flutter 2.12. The null safety thing is new and still confusing to me. For the most part I have been successful in resolving the errors from the migration, but I haven't found a solution for this problem. Here we go:
I have a simple ProductListclass defined as so:
class ProductList {
int count = 0;
List<Product> rows = [];
}
No errors exist in the class. In my main.dart class I am using a ListView to view the list. In the method that creates the ListTile, both of the lines that refer to the productList.rows variable show an error. Here is the code:
eturn ListView.separated(
separatorBuilder: (context, index) => Divider(
color: Colors.black,
),
shrinkWrap: true,
padding: const EdgeInsets.all(2.0),
itemCount: productList.***rows***.length,
itemBuilder: (context, i) {
return _buildRow(productList.***rows***[i]);
});
The error message for those lines is:
The property 'rows' can't be unconditionally accessed because the receiver can be 'null'.
Try making the access conditional (using '?.') or adding a null check to the target ('!').
I have peppered those lines with every combination of '?' and '!' over time, and still no luck. I'm sure I'm overlooking something simple, but I have no idea what that is. I'm new to null safety so Im still at the bottom of the learning curve and most of the official documentation I've found reminds me of reading the K&R (obscure reference for the old programmers in the crowd). Hat am I doing wrong?
change your productList declaration to late ProductList productList;
Related
I am making a simple app which has a model with 2 items in it. I want to access the list in listView builder but it gives an error:
The operator '[]' isn't defined for the class 'FirstSem'.
lib/main.dart:72 - 'FirstSem' is from
'package:project/model/model.dart' ('lib/model/model.dart').
package:project/model/model.dart:1 Try correcting the operator to an
existing operator, or defining a '[]' operator. trailing:
Text(student[index].code)
Suggest me a good way to access it. Thanks in advance.
Here is my code:
model.dart
import 'package:flutter/material.dart';
class FirstSem {
String? title;
String? code;
FirstSem({this.title,this.code});
}
List <FirstSem> subject=[
FirstSem(title: "MatheMatics",code: "MTH162"),
FirstSem(title:"Physice",code:"Phy162"),
FirstSem(title:"Digital Logic",code:"csc 162"),
FirstSem(title:"C Programming",code:"csc 159"),
FirstSem(title:"Introduction of Information Technology",code:"csc 160"),
];
main.dart
ListView.builder(itemCount: 5, itemBuilder: (context, index) {
return ListTile(
title: Text(FirstSem[index].title),
trailing: Text(FirstSem[index].code),
);
})
This is very simple to solve ✔️
You're trying to access item at index index of a dart Class. This is only possible on Lists
Changing your Text(FirstSem[index].title) to Text(subject[index].title) and
Setting your itemCount to subject.length will definitely solve your problem
Happy coding 🎉🎉🎉
FirstSem is class, not object. Change the FirstSem to subject list like this
ListView.builder(
itemCount:subject.length,
itemBuilder: (context,index){
final _subject = subject[index];
return ListTile(
title: Text(_subject.title),
trailing: Text(_subject.code),
);
})
Need help in resolving an exception saying "Bad state: Tried to read a provider that threw during the creation of its value."
The Error!
The following _CastError was thrown building Consumer<CartItemCounter>(dirty, dependencies:
[_InheritedProviderScope<CartItemCounter?>]):
Null check operator used on a null value
The relevant error-causing widget was:
Consumer<CartItemCounter>
Consumer:file:///C:/Users/USER/OneDrive/WebProjects/FLUTTER/PRACTICE/UDEMY/Build_eCommerce_App/e_shop/lib/Sto re/storeHome.dart:69:30
Model File: cartItemCounter.dart
#Am I doing the wrong implementation of the null operator here in this file?
import 'package:e_shop/Config/config.dart';
import 'package:flutter/foundation.dart';
class CartItemCounter extends ChangeNotifier {
int _counter = EcommerceApp.sharedPreferences
!.getStringList(EcommerceApp.userCartList)!
.length -
1;
int get count => _counter;
Future<void> displayResult() async {
int _counter = EcommerceApp.sharedPreferences!
.getStringList(EcommerceApp.userCartList)!
.length -
1;
await Future.delayed(
Duration(milliseconds: 100),
() {
notifyListeners();
},
);
}
}
#Implementation: Consuming the Model on my home page is as below.
Positioned(
child: Stack(
children: [
Icon(
Icons.ac_unit,
size: 20.0,
color: Colors.greenAccent,
),
Positioned(
top: 3.0,
bottom: 4.0,
left: 4.0,
child: Consumer<CartItemCounter>(
builder: (context, counter, child) => Text(
EcommerceApp.sharedPreferences!
.getStringList(EcommerceApp.userCartList)!
.length -
1 as String,
//'${EcommerceApp.sharedPreferences!.getStringList
// (EcommerceApp.userCartList)!.length - 1}',
style: TextStyle(
color: Colors.white,
fontSize: 12.0,
fontWeight: FontWeight.w500),
),
),
)
You used the ! operator a lot. Your compiler is warning you, that in some cases the variables you rely on hold no value, and instead of listening to your compiler and thinking about what you might want your program to do when that is the case, you basically yelled "oh shut the f*** up" and slammed the door by putting in a !. This ! did not solve a single problem though. The variable might still not hold a value, you only yelled at the one tool trying to help you with it to stop doing so. Your program still has unfixed problems, you just suppressed early reporting and now you got late reporting... aka a crash.
Remove all ! used to suppress warnings. Then look at each warning. Why could that variable be null here?
Why is EcommerceApp.sharedPreferences nullable? Well, it's your code, you decide. If you want to keep it as nullable, what do you want to do if it's null?
getStringList returns a list, but it can also return null. For example when you start your app for the first time, there will be no data. How do you want to handle that?
You have to answer those questions, not just tell your compiler to shut up about them. And I cannot answer them for you. It's your program. You decide.
So as an example, instead of this horrible line:
EcommerceApp.sharedPreferences!
.getStringList(EcommerceApp.userCartList)!
.length - 1;
That will fail if either sharedPreferences is null or getStringList returns null, you should think and make decisions what should happen if that is the case. I know the code can be more conscise, but this is a learning exercise, so we will do it the verbose way:
int UserCartListCount() {
final source = EcommerceApp.sharedPreferences;
if(source == null) {
// we have no way to read our data, so what now?
return 0;
}
final cartList = source.getStringList(EcommerceApp.userCartList);
if(cartList == null) {
// there was no cart previously saved
return 0;
}
// this is weird... but it's your logic, I have no idea why that would be correct
return cartList.length - 1;
}
And then, you call this function instead in your code.
After running dart migrate & applying null safety, that error popped up at my code and I think that's the error causing code block.
LayoutBuilder(builder: (context, cons) {
return GestureDetector(
child: new Stack(
children: <Widget?>[
// list of different widgets
.
.
.
].where((child) => child != null).toList(growable: true) as List<Widget>,
),
);
),
The error message says:
The following _CastError was thrown building LayoutBuilder:
type 'List<Widget?>' is not a subtype of type 'List<Widget>' in type cast
The relevant error-causing widget was
LayoutBuilder
package:projectName/…/components/fileName.dart:182
If anyone encountered this issue, how it can be solved?
Although there are different ways to solve it as provided here by #jamesdlin but the recommended one is to use whereType. For example:
List<Widget?> nullableWidgets = [];
List<Widget> nonNullable = nullableWidgets.whereType<Widget>().toList();
To answer your question:
Stack(
children: <Widget?>[
// Widgets (some of them nullable)
].whereType<Widget>().toList(),
)
You cannot use as to cast List<T?> to List<T> because they are not directly related types; you would need to cast the elements instead, using List<Widget>.from() or Iterable.cast<Widget>().
See Dart convert List<String?> to List nnbd for how to remove null elements from a List<T?> and get a List<T> result (and thus avoiding the need to cast later).
Not a Dart expert.
But it seems like the compiler does not respect your null safety checkup.
I suggest creating a new List<Widget> and populate it with each item from List<Widget?> which is not null.
I have this code in my index file:
_ontapd(_navigationLink,BuildContext context){
print(_navigationLink);
}
ListView.builder(
padding: EdgeInsets.only(top: 20),
itemCount: pages.length,
itemBuilder: (context, index) {
return ProfileCard(pages[index],_ontapd(_navigations[index],context));
}),
And this code in "ProfileCard" widget:
String cardText;
Function _onTapFunc;
ProfileCard(#required this.cardText, this._onTapFunc);
GestureDetector(
onTap: _onTapFunc,
...
)
Now whenever I refresh the app, the _onTapFunc gets called for each item in the pages list. Why does this happen?
It's being called because you're calling it in your itemBuilder. It's odd that you're not getting a static analysis error here.
In the line return ProfileCard(pages[index],_ontapd(_navigations[index],context));, you're calling the _ontapd method. Note the parentheses, this means you're calling the method and passing the return value, not passing a reference to it. This value is then being passed to the ProfileCard.
To fix this you need to remove the parentheses. Just pass _ontapd
return ProfileCard(pages[index],_ontapd);
This does result in other issues however. onTap does not have the same parameters your _ontapd method requires, so it cannot be used without modification.
In your current implementation _ontapd just prints the first parameter passed to it, it doesn't even use the second parameter. So a better solution here would be to pass the value of _navigationLink to ProfileCard and define the onTap to print that value. _ontapd could then be completely removed
onTap: () {
print(parameterPassed);
}
The example you provide may be simplified, in which case you hopefully have enough understanding of the error to come to a solution yourself or you'll have to provide more details.
So currently I'm building apps with Flutter which's still new to me, and I'm stuck at that exception in that title.
The problem is when I tried to call "widget.usernames.length" at ListView.builder, it would return that exception if it's null and no exception when there's data.
What I'm trying to accomplish is the get Length function should return null or 0 value so that the ListView would display nothing when there's no data.
return new Expanded(
child: ListView.builder(
padding: new EdgeInsets.all(8.0),
itemExtent: 20.0,
itemCount: widget.usernames.length,
itemBuilder: (BuildContext context, int index){
return Text("Bank ${widget.usernames[index] ?? " "}");
}
),
);
I already tried
itemCount: widget.usernames.length ?? 0
but still no success.
EDIT**
Thanks to Jeroen Heier this code working well.
var getUsernameLength = 0 ;
if(widget.usernames == null){
return getUsernameLength;
}else{
return widget.usernames.length;
}
If you use constructions like "widget.usernames.length" the programming code can fail on two places:
when widget = null
when widget.username = null (your situation)
You cannot call methods and properties on null-objects; that is why you get this error. So before you call widget.usernames.length you must be sure that both situations cannot occur. How this is done and if the check is really necessary depends on the rest of your program. One way to check is:
return widget?.username?.length ?? 0;