Home > Enterprise >  Can't get future builder to display my JSON data
Can't get future builder to display my JSON data

Time:10-01

I am attempting to pull JSON data and display some information in a future builder and listview. The future builder is populating with data but once it gets to the step where listview checks length it fails.

endpoint: https://jsonplaceholder.typicode.com/posts

I am using a public endpoint here is my code:

Main:

import 'package:flutter/material.dart';
import 'package:fresh_project/screens/homepage.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const Homepage(),
    );
  }
}

Homepage (where data is loaded)

import 'package:flutter/material.dart';
import 'package:fresh_project/models/user.dart';
import 'package:fresh_project/network/users_repo.dart';

class Homepage extends StatefulWidget {
  const Homepage({Key? key}) : super(key: key);

  @override
  State<Homepage> createState() => _HomepageState();
}

class _HomepageState extends State<Homepage> {
  late Future<List<User>?>? listOfUsers;
  final UsersRepo _userRepo = UsersRepo();

  @override
  void initState() {
    super.initState();
    listOfUsers = _userRepo.fetchUsers();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<User>?>(
      future: listOfUsers,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          ListView.builder(
            itemCount: snapshot.data!.length,
            itemBuilder: (context, index) {
              return Padding(
                padding: const EdgeInsets.symmetric(vertical: 1, horizontal: 4),
                child: Text(
                  snapshot.data![index].title!,
                ),
              );
            },
          );
        } else if (snapshot.hasError) {
          print('Failed to load users');
        }
        return const Center(
          child: SizedBox(
            width: 200,
            height: 200,
            child: CircularProgressIndicator(),
          ),
        );
      },
    );
  }
}

Repo:

import 'dart:convert';

import 'package:fresh_project/constants/api_constants.dart';
import 'package:http/http.dart' as http;
import 'package:fresh_project/models/user.dart';

class UsersRepo{
  Future<List<User>?> fetchUsers() async {
    try{
      final response = await http.get(Uri.parse(ApiConstants.url   ApiConstants.endpoint));
      if(response.statusCode == 200){
        return returnUsers(response.body);
      }
    } catch(e){
      // ignore: avoid_print
      print(e.toString());
    }
  }
}

List<User> returnUsers(String json){
  List<User> tempList = [];
  var decodedJson = jsonDecode(json);
  for(var instance in decodedJson){
    tempList.add(User.fromJson(instance));
  }
  return tempList;
}

Model:

class User {
  final int? userId;
  final int? id;
  final String? title;
  final String? body;

  User(this.userId, this.id, this.title, this.body);

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      json['userId'],
      json['id'],
      json['title'],
      json['body'],
    );
  }
}

CodePudding user response:

Check for the connection state of the snapshot, and return the progress indicator while the request is running.

Try to reorganize the FutureBuilder like this:

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<User>?>(
      future: listOfUsers,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Center(
            child: SizedBox(
              width: 200,
              height: 200,
              child: CircularProgressIndicator(),
            ),
          );
        }
        if (snapshot.hasData) {
          return ListView.builder(
            itemCount: snapshot.data!.length,
            itemBuilder: (context, index) {
              return Padding(
                padding: const EdgeInsets.symmetric(vertical: 1, horizontal: 4),
                child: Text(
                  snapshot.data![index].title!,
                ),
              );
            },
          );
        } else {
          return const Center(child: Text('Error'));
        }
      },
    );
  }

You can also check for snapshot.hasError if you need.

  • Related