Cannot fetch data from api, Future always returns null - flutter

1,042

Solution 1

The API response is a JSON object

{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

and contains only userId,id, title and completed memebers

instead of referring to an index please consider getting from the object.

replace

snapshot.data[index]

with

 snapshot.data

also

snapshot.data['picture']['large']

you don't have picture data in the JSON object, Try to comment that code or add a picture to it

Solution 2

Before checking for hasData do this:

if (snapshot.connectionState == ConnectionState.done) {
              // your code
}

EDIT

Your request

var result = await http.get(apiUrl+accountNum);

returns JSON object not JSON List. But your fetchData method's return type was List before you updated it to Future<Map<String, dynamic>>. Write your method like this

Future<Map<String, dynamic>> fetchData() async {
    var result = await http.get(apiUrl+accountNum);
    return json.decode(result.body);
}

NO NEED FOR json.decode(result.body)['results'], because you are only fetching an object not a list.

Solution 3

change

title: Text(_MeterNum(snapshot.data[index])),
subtitle: Text(_MeterNum(snapshot.data[index])),
trailing: Text(_MeterNum(snapshot.data[index])),

to

title: Text(_MeterNum(snapshot.data)),
subtitle: Text(_MeterNum(snapshot.data)),
trailing: Text(_MeterNum(snapshot.data)),

there was no key as ['picture']['large'] so comment out the that key in ListTile

Share:
1,042
Kristin Vernon
Author by

Kristin Vernon

Bachelor's Degree in Information Technology, Aspiring Masters student

Updated on December 29, 2022

Comments

  • Kristin Vernon
    Kristin Vernon over 1 year

    I'm trying to fetch data from an API in a flutter. Just to test I was using the API URL: https://jsonplaceholder.typicode.com/todos/1 which has the following JSON object:

    {
      "userId": 1,
      "id": 1,
      "title": "delectus aut autem",
      "completed": false
    }
    

    I followed an example online almost exactly just tweaked to match the workflow I want but the snapshot.hasData below returns false.

    class Home extends StatelessWidget {
      final String accountNum;
      Home(this.accountNum);
      final String apiUrl = "https://jsonplaceholder.typicode.com/todos/";
    
      Future<Map<String, dynamic>> fetchData() async {
        //accountNum below is passed from a previous screen, in this case I pass '1'
        //I printed it to make sure that '1' is passed and it is correct
        var result = await http.get(apiUrl+accountNum);
        //I printed the below and it also gave me the json from the api
        //print(json.decode(result.body));
        return json.decode(result.body);
      }
    
      String _MeterNum(dynamic account){
        return account['title'];
      }
    
    @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Account Data'),
          ),
          body: Container(
            child: FutureBuilder<Map<String, dynamic>>(
              future: fetchData(),
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                if(snapshot.hasData){
                  print(_MeterNum(snapshot.data[0]));
                  return ListView.builder(
                      padding: EdgeInsets.all(8),
                      itemCount: snapshot.data.length,
                      itemBuilder: (BuildContext context, int index){
                        return
                          Card(
                            child: Column(
                              children: <Widget>[
                                ListTile(
                                  leading: CircleAvatar(
                                      radius: 30,
                                      backgroundImage: NetworkImage(snapshot.data[index]['picture']['large'])),
                                  //I realize this will just show the same thing 
                                  //but I was just keeping the format of the example I was following
                                  title: Text(_MeterNum(snapshot.data[index])),
                                  subtitle: Text(_MeterNum(snapshot.data[index])),
                                  trailing: Text(_MeterNum(snapshot.data[index])),
                                )
                              ],
                            ),
                          );
                      });
                }else {
                  return Center(child: CircularProgressIndicator());
                }
              },
    
    
            ),
          ),
        );
      }
    }
    

    What is returned is the CircularProgressIndicator() to the emulator screen indicating that snapshot.hasData is false. I don't get any error in the console or anything so I'm not sure how to proceed.

    ---EDIT--- Made changes to the code above using suggestions from the commenters:

    Changed return type from Future<List> to Future<Map<String, dynamic>> and changed 'return json.decode(result.body)['results'];' to 'return json.decode(result.body)'

    And now I get the following error:

    The following NoSuchMethodError was thrown building FutureBuilder<Map<String, dynamic>>(dirty, state: _FutureBuilderState<Map<String, dynamic>>#a10d4):

    The method '[]' was called on null. Receiver: null

    Tried calling:[] ("title")