首页 > 解决方案 > "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.

标签: flutterdart

解决方案


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

推荐阅读