Flutter 从 API snapshot.hasError 获取数据

Flutter Fetch Data From API snapshot.hasError

现在我尝试从 pexels.com 张照片 api 中获取数据。我在上个月成功完成了这项工作。现在我更新了我的 flutter 版本并再次 运行 这段代码。但是现在这段代码出现了错误。

一直显示snapshot.hasError

我的包裹

import 'dart:convert';
import '../widgets/gridPhotos.dart';
import '../models/photoSearchModel.dart'; //used to decode json by https://app.quicktype.io 
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

状态小部件

class WallpaperScreen extends StatefulWidget {
  @override
  _WallpaperScreenState createState() => _WallpaperScreenState();
}

class _WallpaperScreenState extends State<WallpaperScreen> {
  int page = 1;
  PhotoSearchModel jsonPhotoHTTPGet;
  List<Photo> photos = List<Photo>();
  ScrollController _scrollController = ScrollController();
  @override
  void initState() {
    getWallpapers("wallpaper", page);
    super.initState();
    _sc.addListener(() {
      if (_sc.position.pixels == _sc.position.maxScrollExtent) {
        getWallpapers("wallpaper", page);
      }
    });
  }

从 pexels 获取数据的函数 api

  getCatergoryListWallpapers(int pageNo) async {
    await http.get(
      "https://api.pexels.com/v1/search?query=${widget.catergoryName}&per_page=50&page=${pageNo.toString()}",
      headers: {
        "Authorization":
            "Auth Token" // Auth Token Works 100%
      },
    ).then((value) {
      jsonPhotoHTTPGet = photoSearchModelFromJson(value.body);
      Map<String, dynamic> jsonData = jsonDecode(value.body);
      jsonData["photos"].forEach((element) {
        Photo photosModel = new Photo();
        photosModel = Photo.fromJson(element);
        photos.add(photosModel);
        print(element);
      });
      setState(() {
        page++;
      });
    });
    return photos;
  }

Future Builder 小部件

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<void>(
      future: getCatergoryListWallpapers(page),
      builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
        if (snapshot.hasData) {
          return Container(
            padding: EdgeInsets.all(8),
            child: ListView.separated(
              scrollDirection: Axis.horizontal,
              controller: _scrollController,
              separatorBuilder: (BuildContext context, int index) {
                return SizedBox(
                  width: 10.0,
                  height: double.infinity,
                );
              },
              itemCount: photos.length,
              itemBuilder: (BuildContext context, int index) {
                return Container(
                      // My Code Goes Here
                );
              },
            ),
          );
        } else if (snapshot.hasError) {
          return Center(
            child:Icon(
                  Icons.error_outline,
                  color: Colors.red,
                  size: 60,
            ),
          );
        } else {
          return Center(
            child: CircularProgressIndicator(),
          );
        }
      },
    );

如果我运行这个代码这个return错误大纲图标 并且此代码来自 Future Builder elseif(snapshot.hasError){/* 图标代码 */}

Icon(
  Icons.error_outline,
  color: Colors.red,
  size: 60,
),

PhotoSearch.dart

// Using app.quicktype.io
import 'dart:convert';

PhotoSearchModel photoSearchModelFromJson(String str) =>
    PhotoSearchModel.fromJson(json.decode(str));

String photoSearchModelToJson(PhotoSearchModel data) =>
    json.encode(data.toJson());

class PhotoSearchModel {
  PhotoSearchModel({
    this.totalResults,
    this.page,
    this.perPage,
    this.photos,
    this.nextPage,
  });

  int totalResults;
  int page;
  int perPage;
  List<Photo> photos;
  String nextPage;

  factory PhotoSearchModel.fromJson(Map<String, dynamic> json) =>
      PhotoSearchModel(
        totalResults: json["total_results"],
        page: json["page"],
        perPage: json["per_page"],
        photos: List<Photo>.from(json["photos"].map((x) => Photo.fromJson(x))),
        nextPage: json["next_page"],
      );

  Map<String, dynamic> toJson() => {
        "total_results": totalResults,
        "page": page,
        "per_page": perPage,
        "photos": List<dynamic>.from(photos.map((x) => x.toJson())),
        "next_page": nextPage,
      };
}

class Photo {
  Photo({
    this.id,
    this.width,
    this.height,
    this.url,
    this.photographer,
    this.photographerUrl,
    this.photographerId,
    this.avgColor,
    this.src,
    this.liked,
  });

  int id;
  int width;
  int height;
  String url;
  String photographer;
  String photographerUrl;
  int photographerId;
  String avgColor;
  Src src;
  bool liked;

  factory Photo.fromJson(Map<String, dynamic> json) => Photo(
        id: json["id"],
        width: json["width"],
        height: json["height"],
        url: json["url"],
        photographer: json["photographer"],
        photographerUrl: json["photographer_url"],
        photographerId: json["photographer_id"],
        avgColor: json["avg_color"],
        src: Src.fromJson(json["src"]),
        liked: json["liked"],
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "width": width,
        "height": height,
        "url": url,
        "photographer": photographer,
        "photographer_url": photographerUrl,
        "photographer_id": photographerId,
        "avg_color": avgColor,
        "src": src.toJson(),
        "liked": liked,
      };
}

class Src {
  Src({
    this.original,
    this.large2X,
    this.large,
    this.medium,
    this.small,
    this.portrait,
    this.landscape,
    this.tiny,
  });

  String original;
  String large2X;
  String large;
  String medium;
  String small;
  String portrait;
  String landscape;
  String tiny;

  factory Src.fromJson(Map<String, dynamic> json) => Src(
        original: json["original"],
        large2X: json["large2x"],
        large: json["large"],
        medium: json["medium"],
        small: json["small"],
        portrait: json["portrait"],
        landscape: json["landscape"],
        tiny: json["tiny"],
      );

  Map<String, dynamic> toJson() => {
        "original": original,
        "large2x": large2X,
        "large": large,
        "medium": medium,
        "small": small,
        "portrait": portrait,
        "landscape": landscape,
        "tiny": tiny,
      };
}

现在我的问题是为什么此代码在 flutter 升级 后不起作用?

并且总是 Return 快照错误。

在我的调试控制台中说

E/flutter (12657): 
E/flutter (12657): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: NoSuchMethodError: The method 'forEach' was called on null.
E/flutter (12657): Receiver: null
E/flutter (12657): Tried calling: forEach(Closure: (dynamic) => Null)
E/flutter (12657): #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
E/flutter (12657): #1      _WallpaperScreenState.getWallpapers (package:wallpaperworld/screens/wallpaperScreen.dart:39:24)
E/flutter (12657): <asynchronous suspension>
E/flutter (12657): 
E/flutter (12657): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: NoSuchMethodError: The method 'map' was called on null.
E/flutter (12657): Receiver: null
E/flutter (12657): Tried calling: map(Closure: (dynamic) => Photo)
E/flutter (12657): #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
E/flutter (12657): #1      new PhotoSearchModel.fromJson (package:wallpaperworld/models/photoSearch.dart:29:49)
E/flutter (12657): #2      photoSearchModelFromJson (package:wallpaperworld/models/photoSearch.dart:4:22)
E/flutter (12657): #3      _CategoryListViewBuilderState.getCatergoryListWallpapers.<anonymous closure> (package:wallpaperworld/widgets/categoryPhotos.dart:73:26)
E/flutter (12657): #4      _rootRunUnary (dart:async/zone.dart:1362:47)
E/flutter (12657): #5      _CustomZone.runUnary (dart:async/zone.dart:1265:19)
E/flutter (12657): #6      _FutureListener.handleValue (dart:async/future_impl.dart:152:18)
E/flutter (12657): #7      Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:704:45)
E/flutter (12657): #8      Future._propagateToListeners (dart:async/future_impl.dart:733:32)
E/flutter (12657): #9      Future._completeWithValue (dart:async/future_impl.dart:539:5)
E/flutter (12657): #10     _completeOnAsyncReturn (dart:async-patch/async_patch.dart:254:13)
E/flutter (12657): #11     _withClient (package:http/http.dart)
E/flutter (12657): <asynchronous suspension>

Another exception was thrown: 'package:flutter/src/widgets/basic.dart': Failed assertion: line 3709 pos 15: 'left == null || right == null || width == null': is not
true.

原因很可能是您的授权令牌已过期,它们的预期寿命有限(出于安全原因)。

这是我的猜测,如果您想了解更多详细信息,您应该打印错误。

你也可以尝试在hasError之前添加connectionState条件:

if (snapshot.connectionState == ConnectionState.active && snapshot.hasError)

好的。因此,我尝试使用您的密钥和所有内容访问 API,但出现以下错误:

{
    "error": "Rate limit exceeded"
}

一个建议是不要在您的问题中这样提供您的密钥。二是修复API端的错误。这不是 Flutter 错误。