flutter - "The method '[]' was called on null." When calling an API
问题描述
I am using an API from disease.sh in my COVID-19 tracker project and but when I called worldData ['cases']
in the UI, an error occurred:
The method '[]' was called on null.
Receiver: null
Tried calling: []("cases")
Here is my code:
import 'package:flutter/material.dart';
import 'api.dart';
import 'package:http/http.dart';
import 'dart:convert';
Map worldData;
fetchWorldData() async {
Response response =
await get(Uri.parse('https://disease.sh/v3/covid-19/all'));
worldData = json.decode(response.body);
}
Widget coloredCard() => Card(
shadowColor: Colors.red,
elevation: 8,
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.red[500], Colors.red[500]],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
)),
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Comfirmed',
style: TextStyle(
fontSize: 23,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Text(
worldData['cases'].toString(),
style: TextStyle(
fontSize: 50,
color: Colors.white,
),
),
],
),
),
);
I tried to replace worldData['cases']
with "123"
and the error disappeared.
If you can help me, I will be very grateful.
解决方案
Your fetchWorldData
function is async. You need to handle the UI according to the result of the async function. In this case you can use FutureBuilder
.
I've updated your code with FutureBuilder. It will work, but the FutureBuilder
should be obtained before e.g. in initState
. Please have a look at the code below also.
Future<Map<String, dynamic>> fetchWorldData() async {
Response response =
await get(Uri.parse('https://disease.sh/v3/covid-19/all'));
return json.decode(response.body);
}
Widget coloredCard() => Card(
shadowColor: Colors.red,
elevation: 8,
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.red[500], Colors.red[500]],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
)),
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Comfirmed',
style: TextStyle(
fontSize: 23,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
FutureBuilder<Map<String, dynamic>>(
future: fetchWorldData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(
snapshot.data['cases'].toString(),
style: TextStyle(
fontSize: 50,
color: Colors.white,
),
);
} else {
return Text('there is no data yet');
}
},
),
],
),
),
);
The full example with the good point that was mentioned in comment by Problematic Dude.
The future must have been obtained earlier, e.g. during State.initState, State.didUpdateWidget, or State.didChangeDependencies. It must not be created during the State.build or StatelessWidget.build method call when constructing the FutureBuilder. If the future is created at the same time as the FutureBuilder, then every time the FutureBuilder's parent is rebuilt, the asynchronous task will be restarted.
class FullFutureExample extends StatefulWidget {
@override
_FullFutureExampleState createState() => _FullFutureExampleState();
}
class _FullFutureExampleState extends State<FullFutureExample> {
Future _covidFuture;
@override
void initState() {
super.initState();
_covidFuture = fetchWorldData();
}
@override
Widget build(BuildContext context) {
return coloredCard();
}
Future<Map<String, dynamic>> fetchWorldData() async {
Response response =
await get(Uri.parse('https://disease.sh/v3/covid-19/all'));
return json.decode(response.body);
}
Widget coloredCard() => Card(
shadowColor: Colors.red,
elevation: 8,
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.red[500], Colors.red[500]],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
)),
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Comfirmed',
style: TextStyle(
fontSize: 23,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
FutureBuilder(
future: _covidFuture,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(
snapshot.data['cases'].toString(),
style: TextStyle(
fontSize: 50,
color: Colors.white,
),
);
} else {
return Text('there is no data yet');
}
},
),
],
),
),
);
}
推荐阅读
- jenkins - 矩阵作业工作区文件与父作业工作区不同
- tensorflow - 我在使用 tensorflow 进行车牌识别项目……在训练模型(脚本)时,它说模块错误 pycocotools。安装时说
- jmeter - Jmeter上GUI模式和非GUI模式之间的平均响应时间差异巨大
- snowflake-cloud-data-platform - 雪花中的时间戳转换错误
- python - 如何在python3中根据时间格式对数据进行排序
- python - 使用python弹性附加一个值
- vuejs2 - 在Vue中生成带有图像背景的pdf文件
- sql-server - ApplicationUserManager.Create “找不到请求的 .Net Framework 数据提供程序。它可能没有安装。” 部署到服务器时
- c# - 如何将 dll 正确添加到 .net c# blazor 项目中
- php - OrderWise API 集成