Home > database >  Flutter FutureBuilder snapshot returns Instance of 'Object' instead of data
Flutter FutureBuilder snapshot returns Instance of 'Object' instead of data

Time:10-02

i am new to flutter and trying to display data from a http post

referencing from [1]https://flutter.dev/docs/cookbook/networking/background-parsing and [2]https://flutter.dev/docs/cookbook/networking/fetch-data

i tried to display data on a futurebuilder but it keeps displaying this from the Text('${snapshot.data}')

[Instance of 'DashBoardBanner', Instance of 'DashBoardBanner', Instance of 'DashBoardBanner']

Builder

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  _MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
  late Future<List<DashBoardBanner>> futureBanner;
  @override
  void initState() {
    super.initState();
    futureBanner = getBannerDataFromServer();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
          child: ListView(
            children: [
              Card(
                child: FutureBuilder(
                  future: getBannerDataFromServer(),
                  builder: (context,snapshot){
                    if(snapshot.connectionState == ConnectionState.done){
                      if (snapshot.hasData) {
                        return Text('${snapshot.data}');
                      } else if (snapshot.hasError) {
                        return Text('${snapshot.error}');
                      }
                    }
                    return const CircularProgressIndicator();
                  },
                ),
              )
            ],
          )),
    );
  }
}

Class and postreq

class DashBoardBanner {
  final String MsgId;
  final String MsgKey;
  final String MsgPic;

  const DashBoardBanner(
      {required this.MsgId, required this.MsgKey, required this.MsgPic});

  factory DashBoardBanner.fromJson(Map<String, dynamic> json) {
    return DashBoardBanner(
      MsgId: json['MsgId'] as String,
      MsgKey: json['MsgKey'] as String,
      MsgPic: json['MsgPic'] as String,
    );
  }
}

Future<List<DashBoardBanner>> getBannerDataFromServer() async {
  final queryParameters = {
    "ApiFunc": 'Banner',
    "UserKey": getDeviceKey(),
    "Token": getDeviceToken(),
    "SubmitContent": json.encode({"MobileNo": getMobileNo1()})
  };
  final response = await http.post(
    Uri.http('somesite.net', '/capi.aspx', queryParameters),
  );

  if (response.statusCode == 200) {
    Map<String, dynamic> data = jsonDecode(response.body);
    final splitoff = jsonEncode(data['RespContent']);
    return compute(parseBanner, splitoff);
  } else {
    throw Exception('Failed to load Data');
  }
}

List<DashBoardBanner> parseBanner(String responseBody) {
  final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
  return parsed
      .map<DashBoardBanner>((json) => DashBoardBanner.fromJson(json))
      .toList();
}

Edit : i rebuilt the file replicating reference[1] and it finally displayed the data i needed, it seems the issue stem from not having this 2nd widget which return the obj back , however how do i combine the 2nd build widget into the first without needing the whole widget as having a whole build widget to return 1 line seems pointless?

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body:Container(
        child: FutureBuilder<List<DashBoardBanner>>(
          future: getBannerDataFromServer(http.Client()),
          builder: (context, snapshot) {
            if (snapshot.hasError) {
              return const Center(
                child: Text('An error has occurred!'),
              );
            } else if (snapshot.hasData) {
              print(snapshot.data!.length);
              return DashBoardBannersList(dashboardBanners: snapshot.data!);  <--- original issue due to not having this
            } else {
              return CircularProgressIndicator();
            }
          },
        ),
      ),

    );
  }
}

class DashBoardBannersList extends StatelessWidget {
  const DashBoardBannersList({Key? key, required this.dashboardBanners}) : super(key: key);

  final List<DashBoardBanner> dashboardBanners;

  @override
  Widget build(BuildContext context) {
        return Text(dashboardBanners[0].MsgId); 
  }
}

CodePudding user response:

This error is caused because of the sound null safety

snapshot.data might be null for some requests so you can't access the array at a certain index cause it can be null. If you know for sure snapshot.data exists you can use the ! operator to tell dart the variable is not null for sure like that:

snapshot.data![index];

You can also check if the data is null before accessing it like that:

if (snapshot.data != null) {
    // do something with snapshot.data[index]
}

I recommed to read more about sound null safety here

CodePudding user response:

Check the Firestore docs.

Inside snapshot.data, there's docs (every document of your collection).

The code is from there:

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
      stream: _usersStream,
      builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
        if (snapshot.hasError) {
          return Text('Something went wrong');
        }

        if (snapshot.connectionState == ConnectionState.waiting) {
          return Text("Loading");
        }

        return ListView(
          children: snapshot.data!.docs.map((DocumentSnapshot document) {
          Map<String, dynamic> data = document.data()! as Map<String, dynamic>;
            return ListTile(
              title: Text(data['full_name']),
              subtitle: Text(data['company']),
            );
          }).toList(),
        );
      },
    );
  }

The code above shows how to convert every doc (type DocumentSnapshot) to a JSON format (that can be represented with Map<String, dynamic>). To access to the doc id, you'll access with document.id, because it isn't inside the document.data() method.

CodePudding user response:

You wanna retrieve a list of DashBoardBanner but you forget initialize the futurebuilder by adding a ListView.builder().

Try to use the following code idea :

 FutureBuilder(
            future: getBannerDataFromServer(http.Client()),
            builder: (context, AsyncSnapshot snapshot) {
              print(snapshot.hasData);
              if (snapshot.hasError) {
                return CircularProgressIndicator();
              } else if (snapshot.hasData) {
                return Expanded(
                  child: ListView.builder(
                      scrollDirection: Axis.vertical,
                      itemCount: snapshot.data!.length,
                       itemBuilder: (BuildContext context, int index) {
                        var data = snapshot.data![index];
                        return DashBoardBannersList(dashboardBanners: data);
                          },),
                         ),},
                       },)

  • Related