【问题标题】:retrieve body of json from api从 api 检索 json 的主体
【发布时间】:2020-04-04 00:18:28
【问题描述】:

我正在尝试从位于此处的此 api 返回报价部分:https://api.quotable.io/random

json 看起来像这样:

{"_id":"9hIehvX23pvr","content":"没有魅力等于温柔 ”,“作者”:“简奥斯汀”}

这是连接到 API 的代码部分。

Future<String> _getQuote() async {
  final res = await http.get('https://api.quotable.io/random');
  return json.decode(res.body);
}

每当我运行该应用程序时,我都会收到此错误消息,告诉我它得到了一个空值。但我知道 api 有效。

_FutureBuilderState#b8df9):I/flutter (5315):必须向 Text 小部件提供非空字符串。我/颤振(5315): 'package:flutter/src/widgets/text.dart': I/flutter (5315): 失败 断言:第 269 行 pos 10:'data != null'

我只需要 json 的“内容”部分。我将如何解析那部分?

谢谢!

【问题讨论】:

  • print(res) 在您的问题中输出,您知道您的 API 正在工作,但显然响应为空

标签: flutter dart


【解决方案1】:

@SkyeBoniwell,API 没有得到任何响应。确定有效吗?

截图:

【讨论】:

  • 我刚刚在 Postman 中尝试了 GET 并获得了数据,它会不会暂时停机?
  • 您需要传递正确的标头才能获得响应。它返回一个随机引用,只需在浏览器中打开 URL。
  • @chrisbyte 嗯..出于某种原因,我仍然在 Postman 中遇到同样的错误。 api 的定义错误。
  • 是的,它在我这边工作正常。可能是 API 问题。这就是为什么您必须始终在响应内容解析之前检查 http 响应状态。
【解决方案2】:

您可以在下面复制粘贴运行完整代码
第一步:将&lt;uses-permission android:name="android.permission.INTERNET"/&gt;添加到AndroidManifest
Step2 : 使用如下类解析

Demo demoFromJson(String str) => Demo.fromJson(json.decode(str));
String demoToJson(Demo data) => json.encode(data.toJson());

class Demo {
  String id;
  String content;
  String author;

  Demo({
    this.id,
    this.content,
    this.author,
  });

  factory Demo.fromJson(Map<String, dynamic> json) => Demo(
        id: json["_id"],
        content: json["content"],
        author: json["author"],
      );

  Map<String, dynamic> toJson() => {
        "_id": id,
        "content": content,
        "author": author,
      };
}

工作演示

完整的工作代码

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';

Demo demoFromJson(String str) => Demo.fromJson(json.decode(str));

String demoToJson(Demo data) => json.encode(data.toJson());

class Demo {
  String id;
  String content;
  String author;

  Demo({
    this.id,
    this.content,
    this.author,
  });

  factory Demo.fromJson(Map<String, dynamic> json) => Demo(
        id: json["_id"],
        content: json["content"],
        author: json["author"],
      );

  Map<String, dynamic> toJson() => {
        "_id": id,
        "content": content,
        "author": author,
      };
}

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: FutureBuilderWidget(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

String url = ' http://api.quotable.io/random';

///Method for GET Request
Future<Demo> getDemoResponse() async {
  final response = await http.get('https://api.quotable.io/random');
  print('response ${response}');
  if (response.statusCode == 200) {
    print('response body${response.body}');
    return demoFromJson(response.body);
  } else {
    throw Exception('Failed to load ');
  }
}

class FutureBuilderWidget extends StatefulWidget {
  @override
  _FutureBuilderWidgetState createState() => _FutureBuilderWidgetState();
}

class _FutureBuilderWidgetState extends State<FutureBuilderWidget> {
  bool _isButtonClicked = false;
  var _buttonIcon = Icons.cloud_download;
  var _buttonText = "Fetch Data";
  var _buttonColor = Colors.green;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Container(
          child: Center(
            child: Text(
              'Future Builder Widget',
              style: TextStyle(
                fontSize: 20.0,
                fontWeight: FontWeight.bold,
                //fontFamily: Utils.ubuntuRegularFont
              ),
            ),
          ),
          margin: EdgeInsets.only(right: 48),
        ),
      ),
      body: Center(
        child: FutureBuilder<Demo>(
          ///If future is null then API will not be called as soon as the screen
          ///loads. This can be used to make this Future Builder dependent
          ///on a button click.
          future: _isButtonClicked ? getDemoResponse() : null,
          builder: (context, snapshot) {
            switch (snapshot.connectionState) {

              ///when the future is null
              case ConnectionState.none:
                return Text(
                  'Press the button to fetch data',
                  textAlign: TextAlign.center,
                );

              case ConnectionState.active:

              ///when data is being fetched
              case ConnectionState.waiting:
                return CircularProgressIndicator(
                    valueColor: AlwaysStoppedAnimation<Color>(Colors.blue));

              case ConnectionState.done:

                ///task is complete with an error (eg. When you
                ///are offline)
                if (snapshot.hasError)
                  return Text(
                    'Error:\n\n${snapshot.error}',
                    textAlign: TextAlign.center,
                  );

                ///task is complete with some data
                return Text(
                  'Fetched Data:\n\n${snapshot.data.content}',
                  textAlign: TextAlign.center,
                );
            }
          },
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
      floatingActionButton: FloatingActionButton.extended(
        backgroundColor: _buttonColor,
        onPressed: () {
          ///Calling method to fetch data from the server
          //getDemoResponse();

          ///You need to reset UI by calling setState.
          setState(() {
            _isButtonClicked == false
                ? _isButtonClicked = true
                : _isButtonClicked = false;

            if (!_isButtonClicked) {
              _buttonIcon = Icons.cloud_download;
              _buttonColor = Colors.green;
              _buttonText = "Fetch Data";
            } else {
              _buttonIcon = Icons.replay;
              _buttonColor = Colors.deepOrange;
              _buttonText = "Reset";
            }
          });
        },
        icon: Icon(
          _buttonIcon,
          color: Colors.white,
        ),
        label: Text(
          _buttonText,
          style: TextStyle(color: Colors.white),
        ),
      ),
    );
  }
}

【讨论】:

    猜你喜欢
    • 2015-05-13
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 2012-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多