Flutte – JSON deserialized data fetched to FutureBuilder return null value

Issue

I’m trying to return ListView of photos via FutureBuilder fetched with data from API. While values are added to List in my service and assigned properly, values fetched to List Builder are null. I don’t know why calling service method to return Future<List> returns list of null.

My model:

class Photo {
  String id;
  String photoDesc;
  String photoAuthor;
  String photoUrlSmall;
  String photoUrlFull;
  String downloadUrl;
  int likes;

  Photo(
      {this.id,
      this.photoDesc,
      this.photoAuthor,
      this.photoUrlSmall,
      this.photoUrlFull,
      this.downloadUrl,
      this.likes});

  Photo.fromJson(Map<String, dynamic> json) {
    id = json['id'];
    photoDesc = json['description'] != null
        ? json['description']
        : json['alt_description'];
    photoAuthor = json['user']['name'] != null
        ? json['user']['name']
        : json['user']['username'];
    photoUrlSmall = json['urls']['small'];
    photoUrlFull = json['urls']['full'];
    downloadUrl = json['links']['download'];
    likes = json['likes'];
  }
}

My service:

Future<List<Photo>> getRandomData1() async {
    List<Photo> randomPhotos;
    _response = await http.get(Uri.parse(
        '$unsplashUrl/photos/random/?client_id=${_key.accessKey}&count=30'));
    if (_response.statusCode == 200) {
      return randomPhotos = (json.decode(_response.body) as List).map((i) {
        Photo.fromJson(i); 
        print(Photo.fromJson(i).id); // **i.e. printing returns proper values**
          }).toList();
        } else {
          print(_response.statusCode);
          throw 'Problem with the get request';
        }
      }

My builder:

class RandomPhotosListView extends StatefulWidget {
  @override
  _RandomPhotosListViewState createState() => _RandomPhotosListViewState();
}

class _RandomPhotosListViewState extends State<RandomPhotosListView> {
  final UnsplashApiClient unsplashApiClient = UnsplashApiClient();
  Future _data;

  ListView _randomPhotosListView(data) {
    return ListView.builder(
        itemCount: data.length,
        itemBuilder: (context, index) {
          return Text("${data[index]}"); 
        });
  }

  @override
  void initState() {
    super.initState();
    _data = unsplashApiClient.getRandomData1();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _data,
      builder: (context, snapshot) {
        print(snapshot.data);          // i.e. snapshot.data here is list of nulls
        if (snapshot.connectionState == ConnectionState.waiting) {
          return Center(child: CircularProgressIndicator());
        } else if (snapshot.hasError) {
          print(snapshot.error);
          return Text("error: ${snapshot.error}");
        } else if (snapshot.hasData) {
          return _randomPhotosListView(snapshot.data);
        }
        return Center(child: CircularProgressIndicator());
      },
    );
  }
}

Solution

The reason you are having this issue is because you need to return the parsed object in your mapping function.

Solution #1 – add the return keyword to your existing code

return randomPhotos = (json.decode(_response.body) as List).map((i) {
 return Photo.fromJson(i); // <-- added return keyword here
}).toList();

Solution #2 – Use Arrow to define the return

This solution suits your code since you aren’t manipulating the Photo object or any other data within the mapping.

return randomPhotos = (json.decode(_response.body) as List).map((i) => Photo.fromJson(i)).toList();

Either solution should work. Choose what suits your coding style and your needs.

Answered By – daddygames

Answer Checked By – Gilberto Lyons (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *