将 FutureBuilder 与 Local JSON 用作 Future 时出错

Error Using FutureBuilder With Local JSON as Future

我正在尝试加载一些 json 数据并使用 futurebuilder 等待数据首先可用然后显示它。当我尝试在 DetailsView 中加载数据时,我收到两条日志消息说没有数据和 null,屏幕出现错误,然后 returns 恢复正常并记录 json到控制台。

抛出的异常是The following NoSuchMethodError was thrown building FutureBuilder<String>(dirty, state: _FutureBuilderState<String>#cc31b): The method '[]' was called on null. Receiver: null.

示例代码:

body: Container(
      margin: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 15.0),
      child: FutureBuilder(
        future: DefaultAssetBundle.of(context).loadString("assets/my_data.json"), // validly referenced in pubspec and in right folder
        builder: (context, snapshot){
          if(!snapshot.hasData){
            print('no data'); // I understand it will be empty for now
          } else {
            print('hd');
          }
          var data = snapshot.data.toString();
          print(data); // null logged to console, is the future still empty at this point?
          final parsedData = json.decode(data);
          print('pd ${parsedData[1]}'); // this line is where it shows the method [] was called on null
          return data == null || data.isEmpty
              ? LoadingStrengths()
              : MyDataText();
              // : DailyStrengthText(day: widget.day, data: parsedData);
        },
      ),
    ),

问题似乎是:

  1. 我没有妥善处理未来
  2. 我没有正确解析 json,在下面附上了它的副本。

示例数据:

[{
    "1": "Each day is an opportunity to start over again"
},
{
    "2": "Every man must at one point be tempted to hoist the black"
},
{
    "3": "Be kind to everyone you meet"
}]

我正在尝试通过使用字符串化数字作为键来解析它,以访问值。如何在 Futurebuilder 中为这个 or/and 制作模型 class 解析这个 json?谢谢。

----------------------------编辑------------ -------------------------- 这是经过编辑的构建器方法,我可以从中解析并打印出数据:

if(!snapshot.hasData){
            print('no data yet');
            return LoadingStrengths();
          } else {
            print('hd');
            var data = snapshot.data.toString();
            parsedData = json.decode(data);
            print('pd ${parsedData[widget.day - 1]}');
          }
          return Text('${data[widget.day - 1]}'); // it errors out here

当我将值分配给文本小部件时,它出错并显示以下错误消息:

════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building FutureBuilder<String>(dirty, state: _FutureBuilderState<String>#cc19b):
The method '[]' was called on null.
Receiver: null
Tried calling: [](4)

The relevant error-causing widget was: 
FutureBuilder<String> file:///E:/FlutterProjects/daily_strength/lib/screens/DetailsView.dart:30:18
When the exception was thrown, this was the stack: 
#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1      _DetailsViewState.build.<anonymous closure> 
(package:daily_strength/screens/DetailsView.dart:47:34)
#2      _FutureBuilderState.build 
(package:flutter/src/widgets/async.dart:751:55)
 #3      StatefulElement.build 
(package:flutter/src/widgets/framework.dart:4744:28)
#4      ComponentElement.performRebuild 
(package:flutter/src/widgets/framework.dart:4627:15)

请问这是什么意思?我正在获取数据,但由于某种原因无法将其设置为文本小部件?谢谢。

创建一个单独的 Future 方法(在此处添加所有数据处理)并从 Futurebuilder 中调用它。这可能是导致问题的原因。还要检查 API 是否正常工作,使用 Postman

您在 if 条件之外调用 data。像这样将其包装在else条件中

if (!snapshot.hasData){
    print('no data'); // I understand it will be empty for now
} else {
    print('hd');
    
    var data = snapshot.data.toString();
    print(data); // null wont be logged to console anymore
    final parsedData = json.decode(data);
    print('pd ${parsedData[1]}');
}

您正在尝试解码未加载的 JSON。添加了一些注释以进行解释。

if(!snapshot.hasData) {
  // Problem is here, Data has not arrived yet. You are just printing there is
  // no data, but still moving on the next step
  print('no data');
} else {
  print('hd');
}
// data is null right now, toString() just return 'null' in string form
var data = snapshot.data.toString();

// null logged to console, is the future still empty at this point? yes exactly
print(data); 

// 'null' is parsed has null is returned
final parsedData = json.decode(data); 

// parsedData is null, you can't access using [], when it's null, that why exception is thrown
print('pd ${parsedData[1]}'); 

return data == null || data.isEmpty
              ? LoadingStrengths()
              : MyDataText();

解法:

if(!snapshot.hasData) {
  return LoadingStrengths(); // return a loader when there is not data
} else {
  // Do stuff when it is loaded;
}

这是有问题的:

future: DefaultAssetBundle.of(context).loadString("assets/my_data.json"),

这需要在变量中。想象一下这个 build() 被调用了 30 次。 .loadString 会被调用 30 次,你的 Future 永远不会完成!

始终将您的 Future 放入一个简单的 var 中,并在您的 FutureBuilder 中引用该简单的 var。不要在那里放一个动作。