my snapshot doesn't have the data in futurebuilder - flutter

pls, help if you can .i am trying to fetch some data from rest api .but on the getTreadingWallpapers() method it shows me full json data. but whenever I print snapshot.hasError on else condition.. it shows me false. it means the snapshot has not error..but why i am not getting the data in my future builder. no error showing , how can i solve this problem
class _FrontPageState extends State<FrontPage> {
Future<List<RecentPage>> recentPage;
RecentPage recentPagee;
bool isLoading = true;
List<RecentPage> wallpapers = new List();
Future<List<RecentPage>> getTrendingWallpapers() async {
// final url ="http://wallpaper.pkappstudio.info/api/api.php?action=get_recent";
String url = 'http://wallpaper.pkappstudio.info/api/api.php?action=get_recent';
final response =
await Http.get(url, headers: {"Accept": "application/json"});
if (response.statusCode == 200) {
final Map = jsonDecode(response.body);
print("${response.body}");
isLoading = false;
final recentPaget = recentPageFromJson(response.body).asMap();
recentPaget.entries.forEach((element) => wallpapers.add(element.value));
return wallpapers;
} else {
throw Exception('Failed to load post');
}
}
#override
void initState() {
// TODO: implement initState
recentPage = getTrendingWallpapers();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(title: brandName(),elevation: 0.0,),
body: FutureBuilder(
future: recentPage,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.none &&
snapshot.hasData == null) {
print('project snapshot data is: ${snapshot.data}');
return isLoading? Center(child: Container(child: Text("container"),)):Center(child: Container(child: Text("csdsdontainer"),));
}
if(snapshot.hasData){
return isLoading? Center(child: CircularProgressIndicator()):ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index){
return Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: GridView.count(
shrinkWrap: true,
crossAxisCount: 2,
physics: ClampingScrollPhysics(),
childAspectRatio: 0.6,
mainAxisSpacing: 6.0,
crossAxisSpacing: 6.0,
children: wallpapers.map((wallpapers){
return GridTile(child: GestureDetector(
onTap: (){
// Navigator.push(context, MaterialPageRoute(builder: (context)=>ImageView(
// imageUrl: wallpapers.src.potrait,
// )));
},
child: Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child:Image.network(snapshot.data.imageUrl, fit: BoxFit.cover,),
),
),
));
}).toList(),
),
);
},
);
} else return Container(child: Text("${snapshot.hasError}"),);
},
)
);
}
}

You can copy paste run full code below
Step 1: You do not need isLoading , you can directly use check ConnectionState
Step 2: You do not need to declare List<RecentPage> wallpapers, snapshot.data already keep this
code snippet
builder: (context, AsyncSnapshot<List<RecentPage>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('none');
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (snapshot.hasError) {
return Text(
'${snapshot.error}',
style: TextStyle(color: Colors.red),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: GridView.count(
shrinkWrap: true,
crossAxisCount: 2,
physics: ClampingScrollPhysics(),
childAspectRatio: 0.6,
mainAxisSpacing: 6.0,
crossAxisSpacing: 6.0,
children: snapshot.data.map((wallpapers) {
return GridTile(
child: GestureDetector(
onTap: () {
// Navigator.push(context, MaterialPageRoute(builder: (context)=>ImageView(
// imageUrl: wallpapers.src.potrait,
// )));
},
child: Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
wallpapers.imageUrl,
fit: BoxFit.cover,
working demo
full code
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
List<RecentPage> recentPageFromJson(String str) =>
List<RecentPage>.from(json.decode(str).map((x) => RecentPage.fromJson(x)));
String recentPageToJson(List<RecentPage> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class RecentPage {
RecentPage({
this.no,
this.imageId,
this.imageUpload,
this.imageUrl,
this.type,
this.viewCount,
this.downloadCount,
this.featured,
this.tags,
this.categoryId,
this.categoryName,
});
int no;
String imageId;
String imageUpload;
String imageUrl;
Type type;
String viewCount;
String downloadCount;
Featured featured;
String tags;
String categoryId;
String categoryName;
factory RecentPage.fromJson(Map<String, dynamic> json) => RecentPage(
no: json["no"],
imageId: json["image_id"],
imageUpload: json["image_upload"],
imageUrl: json["image_url"],
type: typeValues.map[json["type"]],
viewCount: json["view_count"],
downloadCount: json["download_count"],
featured: featuredValues.map[json["featured"]],
tags: json["tags"],
categoryId: json["category_id"],
categoryName: json["category_name"],
);
Map<String, dynamic> toJson() => {
"no": no,
"image_id": imageId,
"image_upload": imageUpload,
"image_url": imageUrl,
"type": typeValues.reverse[type],
"view_count": viewCount,
"download_count": downloadCount,
"featured": featuredValues.reverse[featured],
"tags": tags,
"category_id": categoryId,
"category_name": categoryName,
};
}
enum Featured { YES, NO }
final featuredValues = EnumValues({"no": Featured.NO, "yes": Featured.YES});
enum Type { UPLOAD }
final typeValues = EnumValues({"upload": Type.UPLOAD});
class EnumValues<T> {
Map<String, T> map;
Map<T, String> reverseMap;
EnumValues(this.map);
Map<T, String> get reverse {
if (reverseMap == null) {
reverseMap = map.map((k, v) => new MapEntry(v, k));
}
return reverseMap;
}
}
class FrontPage extends StatefulWidget {
#override
_FrontPageState createState() => _FrontPageState();
}
class _FrontPageState extends State<FrontPage> {
Future<List<RecentPage>> recentPage;
RecentPage recentPagee;
bool isLoading = true;
List<RecentPage> wallpapers = new List();
Future<List<RecentPage>> getTrendingWallpapers() async {
// final url ="http://wallpaper.pkappstudio.info/api/api.php?action=get_recent";
String url =
'http://wallpaper.pkappstudio.info/api/api.php?action=get_recent';
final response =
await http.get(url, headers: {"Accept": "application/json"});
if (response.statusCode == 200) {
final Map = jsonDecode(response.body);
print("${response.body}");
isLoading = false;
final recentPaget = recentPageFromJson(response.body).asMap();
recentPaget.entries.forEach((element) => wallpapers.add(element.value));
return wallpapers;
} else {
throw Exception('Failed to load post');
}
}
#override
void initState() {
// TODO: implement initState
recentPage = getTrendingWallpapers();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text("brandName()"),
elevation: 0.0,
),
body: FutureBuilder(
future: recentPage,
builder: (context, AsyncSnapshot<List<RecentPage>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('none');
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (snapshot.hasError) {
return Text(
'${snapshot.error}',
style: TextStyle(color: Colors.red),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: GridView.count(
shrinkWrap: true,
crossAxisCount: 2,
physics: ClampingScrollPhysics(),
childAspectRatio: 0.6,
mainAxisSpacing: 6.0,
crossAxisSpacing: 6.0,
children: snapshot.data.map((wallpapers) {
return GridTile(
child: GestureDetector(
onTap: () {
// Navigator.push(context, MaterialPageRoute(builder: (context)=>ImageView(
// imageUrl: wallpapers.src.potrait,
// )));
},
child: Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
wallpapers.imageUrl,
fit: BoxFit.cover,
),
),
),
));
}).toList(),
),
);
},
);
}
}
}));
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: FrontPage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}

There is a good implementation of a FutureBuilder widget
Future<List<dynamic>> getTrendingWallpapers() async {
String url = 'http://wallpaper.pkappstudio.info/api/api.php?action=get_recent';
final response = await http.get(url, headers: {"Accept": "application/json"});
if (response.statusCode == 200) {
List<dynamic> wallpapers = List();
wallpapers.add(response.body);
return wallpapers;
} else {
throw Exception('Failed to load post');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: getTrendingWallpapers(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting || snapshot.connectionState == ConnectionState.none) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(
child: Text('Future error'),
);
}
if (snapshot.hasData) {
return Center(
child: Text('Do something with your snapshot.data : \n ${snapshot.data}'),
);
}
},
),
);
}

Related

I am trying to fetch collection from shopify admin api with rest api in flutter

I am Using flutter with http package. in my code CircularProgressIndicator() is running and is not showing any error
here is my http request code
import 'package:http/http.dart' as http;
import 'dart:convert';`
class Collections {
Future<List> getAllCollections() async {
var headers = {
'Content-Type': 'application/json',
'X-Shopify-Access-Token': '{token}',
};
var url = Uri.parse(
'https://{shop}.myshopify.com/admin/api/2022-07/collections.json');
try {
var res = await http.get(url, headers: headers);
print(res);
if (res.statusCode == 200) {
return jsonDecode(res.body);
} else {
return Future.error("Server Error");
}
} catch (SocketException) {
return Future.error("Error Fetching Data");
}
}
}
and here I created the object of this class and using it.
class ProCategories extends StatefulWidget {
const ProCategories({Key? key}) : super(key: key);
#override
State<ProCategories> createState() => _ProCategoriesState();
}
class _ProCategoriesState extends State<ProCategories> {
Collections collections = Collections();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Categories"),
centerTitle: true,
foregroundColor: Colors.black,
backgroundColor: Colors.white,
),
body: Container(
margin: EdgeInsets.only(top: 8.0),
child: FutureBuilder<List>(
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data?.length == 0) {
return Center(
child: Text("0 Collections"),
);
}
return ListView.builder(
itemCount: snapshot.data?.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Row(
children: [
Expanded(
child: Container(
child: Text(
snapshot.data![index]['collections']['edges']
['node']['title'],
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold),
),
),
),
],
),
),
);
});
} else if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString()),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
),
);
}
}
Add future to FutureBuilder.
late Future<List> getAllCollections;
#override
void initState() {
super.initState();
getAllCollections = collections.getAllCollections();
}
#override
Widget build(BuildContext context) {
return Scaffold(
...
body: Container(
margin: EdgeInsets.only(top: 8.0),
child: FutureBuilder<List>(
future: getAllCollections,
builder: (context, snapshot) {
...
},
),
),
);
}
See Fetch data from the internet for the full example.

FutureBuilder operated without initState in flutter

I work with FutureBuilder to view a set of data through GridView by FutureBuilder but there are one problem the data is view without put method in initState().I don't know why it works without putting it in initState().
full code:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
bool showicon = false;
var apiURL;
Future getdataCat() async {
setState(() {
showicon = true;
});
apiURL = '***********************';
var response = await http.post(Uri.parse(apiURL));
var responsebody = jsonDecode(response.body);
if (responsebody.length > 0) {
return responsebody;
} else {
showicon = false;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: <Widget>[
Flexible(
child: FutureBuilder(
future: getdataCat(),
builder: (context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
// still waiting for data to come
return showicon
? Center(
child: CircularProgressIndicator(
color: Colors.black,
))
: SizedBox(
height: 10,
child: Center(
child: Image.asset(
'assets/data.png',
)));
} else if (snapshot.hasData &&
snapshot.data.isEmpty &&
snapshot.data <= 0) {
return SizedBox(
height: 10,
child: Center(
child: Image.asset(
'assets/data.png',
)));
} else {
return GridView.builder(
physics: ScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, childAspectRatio: 3.4),
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Container(
child: Card(
child: Column(
children: <Widget>[
Flexible(
child: GestureDetector(
child: Column(children: <Widget>[
Center(
child: Text(
"${snapshot.data[index]['name']}"))
]),
)),
],
),
),
);
},
);
}
},
),
)
],
),
),
);
}
}
As you can see I not make any thing in initState() but it's still working.
I need to stop it if I don't put it in initState().Because I need to run a different function before it.
I prefer this way. You can check Randal L. Schwartz video
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late final Future<List<int>?> myFuture;
#override
void initState() {
super.initState();
myFuture = getCatData();
}
Future<List<int>?> getCatData() async {
await Future.delayed(Duration(seconds: 2));
//your operations
return [1, 2, 5];
// return [];
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(onPressed: () {
setState(() {});
}),
body: Center(
child: Column(
children: <Widget>[
Flexible(
child: FutureBuilder<List<int>?>(
future: myFuture,
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text("Error ${snapshot.error}");
}
if (!snapshot.hasData) {
return Text("no Data found");
}
if (snapshot.data!.isEmpty) {
return Text("Empty found");
}
if (snapshot.hasData) {
return GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 3.4,
),
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Container(
child: Text(snapshot.data[index].toString()));
},
);
}
return Text("NA");
},
),
)
],
),
),
);
}
}
Point of FutureBuilder is to run a function that will return with the data you want to use to build your widgets.
You already call your method in the FutureBuilder:
FutureBuilder(
future: getdataCat(),
builder: (context, AsyncSnapshot snapshot) {...}
)

Flutter error : Got the error on length and map

I Got the error on length and map after upgrading flutter.
And the same code is running in the old project.
when I print only snapshot.data then data is not showing.
class _TabPageState extends State<TabPage> {
var response;
var medicineSubCategoryApi;
#override
void initState() {
super.initState();
fetchData(widget.medicineCatUniqId);
}
fetchData(var medicineCatUniqId) async {
var api = Uri.parse($baseUrl/productSubCatApi.php?a2rTokenKey=$a2rTokenKey&pcat=$medicineCatUniqId');
response = await http.get(
api,
);
print("medicineCatApiLnk " + api.toString());
print("medicineCat" + response.body);
medicineSubCategoryApi = jsonDecode(response.body);
print("medicineCatString" + medicineSubCategoryApi.toString());
return medicineSubCategoryApi;
// setState(() {});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: FutureBuilder(
future: fetchData(medicineSubCategoryApi),
// initialData: medicineSubCategoryApi,
builder: (context, snapshot) {
if (snapshot.hasData) {
print(snapshot.data.length.toString());
print(snapshot.data.toString());
// API data will be stored as snapshot.data
return DefaultTabController(
length: snapshot.data.length,
child: Scaffold(
appBar: AppBar(
title: const Text('Tabbed AppBar'),
bottom: TabBar(
isScrollable: true,
tabs: snapshot.data
.map<Widget>((choice) => Tab(
text: choice['psubCatName'],
// icon: Icon(choice),
))
.toList(),
),
),
body: TabBarView(
physics: NeverScrollableScrollPhysics(),
children: snapshot.data.map<Widget>((choice) {
return Padding(
padding: const EdgeInsets.all(20.0),
child: ChoicePage(
choice: choice,
),
);
}).toList(),
),
),
);
} else if (snapshot.hasError) {
return Text('Error');
} else {
return Text('Loading');
}
}),
);
}
}
class ChoicePage extends StatelessWidget {
const ChoicePage({Key? key, this.choice}) : super(key: key);
final choice;
#override
Widget build(BuildContext context) {
final TextStyle? textStyle = Theme.of(context).textTheme.headline4;
return Card(
color: Colors.white,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
choice['psubCatName'],
style: textStyle,
),
],
),
),
);
}
}
when I print This thing I got then coming error.
class _TabPageState extends State<TabPage> {
var response;
var medicineSubCategoryApi;
#override
void initState() {
super.initState();
// for loading
fetchData(widget.medicineCatUniqId);
}
fetchData(var medicineCatUniqId) async {
var api = Uri.parse('$baseUrl/productSubCatApi.php?a2rTokenKey=$a2rTokenKey&pcat=$medicineCatUniqId');
response = await http.get(
api,
);
print("medicineCatApiLnk " + api.toString());
print("medicineCat" + response.body);
// in double quotes drink is key value of json
medicineSubCategoryApi = jsonDecode(response.body);
print("medicineCatString" + medicineSubCategoryApi.toString());
return medicineSubCategoryApi;
// setState(() {});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: FutureBuilder(
future: fetchData(medicineSubCategoryApi),
// initialData: medicineSubCategoryApi,
builder: (context, snapshot) {
if (snapshot.hasData) {
print(snapshot.data.length.toString());
print(snapshot.data.toString());
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(snapshot.data.length.toString()),
Text(snapshot.data.toString()),
],
);
// API data will be stored as snapshot.data
}).toList(),
),
),
);
} else if (snapshot.hasError) {
return Text('Error');
} else {
return Text('Loading');
}
}),
);
}
}
try this
print(snapshot.data!.length!.toString());
print(snapshot.data!.toString());
it can solve the problem if you were not using Flutter 2.0 before

Flutter: not being able to show all incoming data

I was using shared_preferences plugin in my Flutter application, I set my data when I click the button, but I try to get my data is not coming.
I set my data here and when I print it, I can see the output on my console.
shows.forEach((element) {
showCode=element.showName;
show.setString('showName', showCode);
});
I want to get my data here, above the override method. But when I print here, I just see 1 item, but I need to print 2 items.
String showCode;
Future<String> getCode() async{
final codeValue = await SharedPreferences.getInstance();
setState((){
showyCode =codeValue.getString('showName');
});
print('here $showCode');
return showCode;
}
But I cannot call this future in my function, even if I have 2 data to come but I just see 1 item. I tried to include it in Listview then it fills an entire list with 1 item. Anyone have an idea where I'm doing wrong?
_showProgramData
? Container(
height: MediaQuery.of(context).size.height/2,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
IconButton(icon:Icon(Icons.close) , onPressed:() {Navigator.pushNamed(context, SecondScreen.routeName);}),
Text('Please Select Show',style: TextStyle(fontWeight:FontWeight.bold,fontSize: 24),),
],
),
Text(showCode),
],
),
),
)
You can copy paste run full code below
Step 1: You need to use setStringList and getStringList
Step 2: getCode() return Future<List<String>>
Step 3: In forEach use showCodeList.add(element.showName);
code snippet
void _setData() async {
shows.forEach((element) {
showCodeList.add(element.showName);
});
final codeValue = await SharedPreferences.getInstance();
await codeValue.setStringList('showName', showCodeList);
setState(() {});
}
Future<List<String>> getCode() async {
final codeValue = await SharedPreferences.getInstance();
showCodeList = await codeValue.getStringList('showName');
if (showCodeList == null) {
showCodeList = [];
}
print('here ${showCodeList.toString()}');
return showCodeList;
}
...
FutureBuilder(
future: _future,
builder: (context, AsyncSnapshot<List<String>> snapshot) {
...
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Card(
elevation: 6.0,
child: Padding(
padding: const EdgeInsets.only(
top: 6.0, bottom: 6.0, left: 8.0, right: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(snapshot.data[index]),
working demo
full code
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() async{
WidgetsFlutterBinding.ensureInitialized();
final codeValue = await SharedPreferences.getInstance();
await codeValue.setStringList('showName', []);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class Show {
String showName;
Show({this.showName});
}
class _MyHomePageState extends State<MyHomePage> {
Future<List<String>> _future;
List<Show> shows = [Show(showName: "a"), Show(showName: "b")];
String showCode;
List<String> showCodeList = [];
void _setData() async {
shows.forEach((element) {
showCodeList.add(element.showName);
});
final codeValue = await SharedPreferences.getInstance();
await codeValue.setStringList('showName', showCodeList);
setState(() {});
}
Future<List<String>> getCode() async {
final codeValue = await SharedPreferences.getInstance();
showCodeList = await codeValue.getStringList('showName');
if (showCodeList == null) {
showCodeList = [];
}
print('here ${showCodeList.toString()}');
return showCodeList;
}
#override
void initState() {
_future = getCode();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: FutureBuilder(
future: _future,
builder: (context, AsyncSnapshot<List<String>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('none');
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (snapshot.hasError) {
return Text(
'${snapshot.error}',
style: TextStyle(color: Colors.red),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Card(
elevation: 6.0,
child: Padding(
padding: const EdgeInsets.only(
top: 6.0, bottom: 6.0, left: 8.0, right: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(snapshot.data[index]),
],
),
));
});
}
}
}),
floatingActionButton: FloatingActionButton(
onPressed: _setData,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

Set state from FutureBuilder in Flutter

I've been trying to set a property based on a response from a FutureBuilder but can't seem to get it working. How can I set _activityLength after the future resolves without setting during build?
FutureBuilder<QuerySnapshot>(
future: _future,
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Press button to start');
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(),
);
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
final documents = snapshot.data.documents;
_activityLength = documents.length;
return Expanded(
child: ListView.separated(
shrinkWrap: true,
separatorBuilder: (context, index) => Divider(
color: Colors.black,
height: 0,
),
itemCount: documents.length,
itemBuilder: (context, index) => _activityTile(
documents[index],
),
),
);
}
}
},
)
The FutureBuilde is in a Column widget in the body of the Scaffold and the value that I need to set is in the _itemsHeaderText Something like this:
body:
...
child: Column(
children: <Widget>[
Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(
bottom:
BorderSide(color: Colors.grey, width: 1.0),
),
),
child: Padding(
padding: const EdgeInsets.only(
left: 15.0,
right: 15.0,
top: 10.0,
bottom: 10.0),
child: _itemsHeaderText(),
),
),
_itemsBody(),
],
),
You can copy paste run full demo code below
You can use _future.then((value) in initState() and do job in addPostFrameCallback like setState
And after future resolves, you can get value of _future, you can do further processing if need
In demo code, I get value length and display on screen
You can see working demo, data length change from 0 to 9
code snippet
#override
void initState() {
super.initState();
_future = _getUsers();
_future.then((value) {
print("data length ${value.length}");
WidgetsBinding.instance.addPostFrameCallback((_) {
print("other job");
setState(() {
_dataLength = value.length;
});
});
});
}
working demo
output
I/flutter (18414): data length 9
I/flutter (18414): other job
full code
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: CategoryTab(title: 'Flutter Demo Home Page'),
);
}
}
class CategoryTab extends StatefulWidget {
CategoryTab({Key key, this.title}) : super(key: key);
final String title;
#override
_CategoryTabState createState() => _CategoryTabState();
}
class _CategoryTabState extends State<CategoryTab> {
Future<List<CategoryList>> _future;
int _dataLength = 0;
Future<List<CategoryList>> _getUsers() async {
var data = await http
.get("https://appiconmakers.com/demoMusicPlayer/API/getallcategories");
var jsonData = json.decode(data.body);
List<CategoryList> cat = [];
for (var u in jsonData) {
CategoryList categoryList = CategoryList(
u["category_id"],
u["category_name"],
u["parent_category_id"],
u["category_status"],
u["created_date"]);
cat.add(categoryList);
}
return cat;
}
#override
void initState() {
super.initState();
_future = _getUsers();
_future.then((value) {
print("data length ${value.length}");
WidgetsBinding.instance.addPostFrameCallback((_) {
print("other job");
setState(() {
_dataLength = value.length;
});
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Categories",
style: TextStyle(color: Colors.black),
),
backgroundColor: Colors.white,
),
body: Column(
children: [
Text("data length $_dataLength"),
Expanded(
child: Container(
child: FutureBuilder(
future: _future,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Container(child: Center(child: Text("Loading...")));
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(),
title: Text(
"${snapshot.data[index].categoryName}",
// subtitle: Text(snapshot.data[index].categoryId
),
);
},
);
}
},
),
),
),
],
),
);
}
}
class CategoryList {
String categoryId;
String categoryName;
String parentCategoryId;
String categoryStatus;
String createdDate;
CategoryList(this.categoryId, this.categoryName, this.parentCategoryId,
this.categoryStatus, this.createdDate);
}
There are a few workarounds to your question.
You could hoist the futureBuilder up the widget tree, instead of setting state the state will be reset once ConnectionState.done.
You could place the future in a function that is called on init state, then the result of the future you set state on it.