简体   繁体   中英

Flutte - JSON deserialized data fetched to FutureBuilder return null value

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());
      },
    );
  }
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM