The getter was called on null - flutter

I am trying to display the list of hobbies of the user from firestore and I get the value from there as it gets print in console but not able to display it.
Error:-
The getter 'hobbies' was called on null.
Receiver: null
Tried calling: hobbies
Create account data is model class:-
Future<CreateAccountData> getUser() async {
final User user = auth.currentUser;
return _reference.doc(user.uid).get().then((m) => CreateAccountData.fromDocument(m));
}
getting data this way and it gets print also in console:-
List hobbies;
void initState() {
super.initState();
getUser().then((value) {
if (!mounted) return;
setState(() {
accountData = value;
hobbies = value.hobbies;
print("hobbies"+ hobbies.toString());
});
});
}
Error takes me to the line I commented:-
child:GridView.builder(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: accountData.hobbies.length, // Error take me to hobbies.
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: 5, crossAxisSpacing: 5,),
itemBuilder: (BuildContext context, int index){
return Padding(
padding: EdgeInsets.fromLTRB(5, 5, 5, 5),
child: Text(accountData.hobbies[index]),
);
}
),
On suggestions updated to this(wrapped in future builder):-
child: FutureBuilder(
future: getUser(),
builder: (context, snapshot){
if(snapshot.connectionState == ConnectionState.waiting){
return Center(
child: CircularProgressIndicator(),
);
} if(snapshot.data.docs.isEmpty){
return Align(
alignment: FractionalOffset.centerLeft,
child: Text("Add what you love to do.....",textAlign: TextAlign.left,style: TextStyle(fontSize: 17),),
);
}
return GridView.builder(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: accountData?.hobbies?.length ?? 0,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 5,
crossAxisSpacing: 5,),
itemBuilder: (BuildContext context,
int index) {
return Padding(
padding: EdgeInsets.fromLTRB(5, 5, 5, 5),
child: Text(accountData.hobbies[index]),
);
}
);
},
),
Now getting NoSuchMethodError error:-
Class 'CreateAccountData' has no instance getter 'docs'.
Receiver: Instance of 'CreateAccountData'
Tried calling: docs

check hobbies is null
itemCount: accountData?.hobbies?.length ?? 0,

In flutter 2.0, we have null safety. We need to check if value is null or not using an ! mark after the variable. I will post the code in a few minutes since Im in school rn

Wrap GridView.builder in a FutureBuilder passing getUser() as the future.
child: FutureBuilder(
future: getUser(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return CircularProgressIndicator();
if (snapshot.hasData)
return GridView.builder(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount:
snapshot.data.hobbies.length, // Error take me to hobbies.
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 5,
crossAxisSpacing: 5,
),
itemBuilder: (BuildContext context, int index) {
//DocumentSnapshot interestList = snapshot.data.docs[index]['hobbies'];
return Padding(
padding: EdgeInsets.fromLTRB(5, 5, 5, 5),
child: Text(snapshot.data.hobbies[index]),
);
});
return Text('No data.');
},
),

Related

How to use future builder in slivers in flutter

I want to display data from the api in the slivers using future builder with grid layouts. I tried but i could not do that.
Here is the code
slivers: [
SliverGrid(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text('grid item $index'),
);
},
childCount: 10,
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 15,
crossAxisSpacing: 15,
childAspectRatio: 2.0,
),
)
],
I tried this way. but child count is the problem
SliverGrid(
delegate: SliverChildBuilderDelegate(
(context, index) {
return FutureBuilder(
future: getProducts(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
return Container(
child: Text(
'Hello',
),
);
},
);
},
childCount: 10,
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 15,
crossAxisSpacing: 15,
childAspectRatio: 2.0,
),
)
get that future and build the delegate inside your FutureBuilder
FutureBuilder(
future:YourApi(),
builder:(_,snap){
if(snap.hasData){
//get your data , if its json, decode and make it into a class
List<T> data = snap.data .......
return ....(
slivers:[
SliverGrid(
......
,childCount: data.lenght
)
]
)
} else {}
}
)
You can directly use FutureBuilder inside slivers. just make sure the return widget is needed to be a sliver widget on every case.
body: CustomScrollView(
slivers: [
FutureBuilder<List<int>>(
/// create a future variable on state class
future: Future.delayed(Duration(seconds: 2))
.then((value) => List.generate(11, (i) => i)),
builder: (context, snapshot) {
if (snapshot.hasData) {
return SliverGrid(
delegate: SliverChildBuilderDelegate(
childCount: snapshot.data?.length,
(context, index) => Container(
child: Text("${snapshot.data?[index]}"),
),
),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2));
}
return const SliverToBoxAdapter(
child: CircularProgressIndicator(),
);
},
)
],
),

How do I remove all the spaces between the card in gridview.builder

I need help regarding my gridview.builder, my gridview become like this, this happened because I want to filter to show only item that has the same id. I already try to put padding: EdgetInsets.zeroand SizedBox.shrink but it still does not work. How can I remove the blank card and only show the visible card? if I remove return Card()
Stack(
children: [
StreamBuilder(
stream: FirebaseFirestore.instance.collection('products').snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot){
if(snapshot.hasError){
return Text("Error: ${snapshot.error}");
}
if(snapshot.hasData){
return Column(
children: [
Flexible(
child: GridView.builder(
padding: EdgeInsets.zero,
itemCount: snapshot.data!.docs.length,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 15,
crossAxisSpacing: 15,
childAspectRatio: 2/3,
),
itemBuilder: (context, index){
final DocumentSnapshot documentSnapshot =
snapshot.data!.docs[index];
DateTime dt = (documentSnapshot['endDateTime'] as Timestamp).toDate();
if(documentSnapshot['userid'] == widget.sellerId){
print(documentSnapshot['userid']);
return buildImageCard(
documentSnapshot['imageURL'][0], documentSnapshot['nameP'],
documentSnapshot['startPrice'], dt, documentSnapshot['id'],
documentSnapshot['categoryP']);
}
return Card();
}
)
),
],
);
}
return const Center(
child: CircularProgressIndicator(),
);
}
),
],
);
The solution would be to filter the list of docs above the widget, and use the filtered list for itemCount and the builder.
The cause of the issue is that each widget takes the aspect ratio that your specified (2/3) + the spacing regardless of the size of the child widget.
So it should be a little something like this
if(snapshot.hasData){
final listToUse = snapshot.data?.docs.where((documentSnapshot) => documentSnapshot['userid'] == widget.sellerId).toList() ?? [];
return Column(...

App crashes when load a lot of data inside a gridview

Description
I'm using a gridview to show the products of a market and when a scroll the gridview nine times my app crashes.
The widget build of this screen return a SmartRefresher wrapped a GridView.
return SmartRefresher(
controller: controller.refreshController,
onLoading: controller.onLoading,
onRefresh: controller.onRefresh,
enablePullUp: true,
child: Observer(builder: (context) {
return GridView.builder(
padding: EdgeInsets.only(top: 10),
shrinkWrap: true,
cacheExtent: 100,
physics: ScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount:
MediaQuery.of(context).orientation == Orientation.portrait
? 2
: 3,
crossAxisSpacing: 5.0,
mainAxisSpacing: 5.0,
childAspectRatio: 0.85,
),
itemCount:
controller.produtos == null ? 0 : controller.produtos.length,
itemBuilder: (context, index) {
Produto produto = controller.produtos[index];
//here I return my card
},
);
}),
);
Note: If I remove the SmartRefresher I can scroll the GridView with a lot of data.
Try to place the Observer above SmartRefresher, like this:
Observer(
builder: (context) {
return SmartRefresher(
controller: controller.refreshController,
onLoading: controller.onLoading,
onRefresh: controller.onRefresh,
enablePullUp: true,
child: GridView.builder(
padding: EdgeInsets.only(top: 10),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount:
MediaQuery.of(context).orientation == Orientation.portrait
? 2
: 3,
crossAxisSpacing: 5.0,
mainAxisSpacing: 5.0,
childAspectRatio: 0.85,
),
itemCount:
controller.produtos == null ? 0 : controller.produtos.length,
itemBuilder: (context, index) {
Produto produto = controller.produtos[index];
},
),
);
},
);

Why GridView.builder clear when obtain more data in flutter

I have my GRidView builder and I have my future and my ScrollController, why my gridView clear when scrollController is equal than mi maxScroll and obtain more information? It's supposed to show all of it, not the latest information.
this is my code
future: _future ,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.hasData){
List<dynamic> loaded = snapshot.data;
return
Container(
width: double.infinity,
height: _screenSize.height * .8,
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: MediaQuery.of(context).size.width /(MediaQuery.of(context).size.height /1.5),),
controller: _controller,
itemCount: loaded.length,
itemBuilder: (context, i){
return _row(context,loaded,i);
},
)
);
}else{
and the constructor
Future<List> _future;
ScrollController _controller = ScrollController(initialScrollOffset: 0.0, keepScrollOffset: true);
_SearchPageState(){
_controller.addListener(() {
if(_controller.position.pixels >= _controller.position.maxScrollExtent-30 ){
setState(() {
_future = videoJuegos.getPaginationPopular();
});
}
});
_future = videoJuegos.getPaginationPopular();
}
Your Gridview.builder is clearing because of this line:
List<dynamic> loaded = snapshot.data;
It will clear the current list and add the new data. You should use initialize your list above the future and then use list.add:
List<dynamic> loaded = [];
future: _future ,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.hasData){
loaded.add(snapshot.data);
return
Container(
width: double.infinity,
height: _screenSize.height * .8,
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: MediaQuery.of(context).size.width /(MediaQuery.of(context).size.height /1.5),),
controller: _controller,
itemCount: loaded.length,
itemBuilder: (context, i){
return _row(context,loaded,i);
},
)
);
}else{
Hope that helps.

How to increment a list variable based on item index?

im getting an error: type int is not a subtype of type List<dynamic> of function result on pressing add
final itemcount = [];
Widget buildItem(BuildContext context, DocumentSnapshot document, int index) {
return Container(
child: Flatbutton(
child:Text("add"),
onpressed:(){
itemcount[index]=itemcount[index]+1,
}
)
);
}
StreamBuilder<QuerySnapshot>(
stream: Firestore.instance
.collection('products')
.where('category', isEqualTo: 'ourstore')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: Icon(Icons.photo_library),
);
} else {
return snapshot.data.documents.isEmpty
? Center(child: null)
: GridView.builder(
itemBuilder: (context, index) => buildItem(
context,
snapshot.data.documents[index],
index),
itemCount: snapshot.data.documents.length,
physics: NeverScrollableScrollPhysics(),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
// childAspectRatio: 3/4,
crossAxisSpacing: 10,
mainAxisSpacing: 5,
crossAxisCount: 2),
shrinkWrap: true,
scrollDirection: Axis.vertical,
);
}
},
),
fixed the error
had to set the value to zero for every item in the list
code below:
List<int> itemcount = List<int>();
Widget buildItem(
BuildContext context, DocumentSnapshot document, int index) {
itemcount.add(0);
return Container(
child: Flatbutton(
child:Text("add"),
onpressed:(){
setState(() {
itemcount[index]++;
});
}
)
);
}