【问题标题】:Flutter/Dart: Field 'futureAlbum' has not been initializedFlutter/Dart:字段“futureAlbum”尚未初始化
【发布时间】:2021-11-30 18:16:22
【问题描述】:

model_album.dart

class Album {
  final int userId;
  final int id;
  final String title;

  Album({
    required this.userId,
    required this.id,
    required this.title,
  });

  factory Album.fromJson(Map<String, dynamic> json) {
    return Album(
      userId: json['userId'],
      id: json['id'],
      title: json['title'],
    );
  }
}

http_controller.dart


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

import 'package:http/http.dart' as http;
import 'package:feed/models/model_album.dart';

class HttpController extends GetxController {

  late Future<Album> futureAlbum;

  @override
  void onInit() {
    super.onInit;
    futureAlbum = fetchAlbum();
  }

  Future<Album> fetchAlbum() async {
    final response = await http
        .get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));

    if (response.statusCode == 200) {
      // If the server did return a 200 OK response,
      // then parse the JSON.
      debugPrint('futureAlbum initialized');
      return Album.fromJson(jsonDecode(response.body));
    } else {
      // If the server did not return a 200 OK response,
      // then throw an exception.
      throw Exception('Failed to load album');
    }
  }
}

view_http.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';

import 'package:feed/views/view_http.dart';
import 'package:feed/models/model_album.dart';
import 'package:feed/controllers/http_controller.dart';

class ViewHttp extends StatelessWidget {

  var httpController = HttpController();

  @override
  Widget build(BuildContext context) {
    return Center(
        child: FutureBuilder<Album>(
      future: httpController.futureAlbum,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return Text(snapshot.data!.title);
        } else if (snapshot.hasError) {
          return Text('${snapshot.error}');
        }

        // By default, show a loading spinner.
        return const CircularProgressIndicator();
      },
    ));
  }
}

我正在尝试学习如何使用 Getx 和网络请求。我从以下代码中获取了此代码: https://flutter.dev/docs/cookbook/networking/fetch-data

我尝试修改以使用 Getx 并得到错误: LateInitializationError:字段“futureAlbum”尚未初始化。 我认为 onInit 方法应该在 view_http.dart 文件中实例化控制器时初始化。想法?

【问题讨论】:

  • late 关键字仅在您确定该值不为空时使用,因此您可以使用Future&lt;Album?&gt;? futureAlbum;
  • 谢谢。我添加了它,它是 null 并且没有在 onInit 方法中初始化,这是我认为它应该做的。想法?

标签: flutter dart flutter-getx


【解决方案1】:

我认为您不需要 HttpController 中的 futureAlbum。只需删除它,并将代码从httpController.futureAlbum 更改为future: httpController.fetchAlbum。另一种选择是,将您的 ViewHttp 更改为 StatefulWidget,然后将 futureAlbum 放在那里

late Future<Album> futureAlbum;
late HttpController httpController;

  @override
  void onInit() {
    super.onInit;
    httpController = HttpController();
    futureAlbum = httpController.fetchAlbum();
  }

然后在未来的构建器中,使用future: futureAlbum。希望对您有所帮助。

【讨论】:

  • 感谢您的建议。我尝试将httpController.futureAlbum 更改为future: httpController.fetchAlbum。我收到错误“参数类型 'Future Function()' 不能分配给参数类型 'Future?” " 我正在尝试仅使用带有 Getx 包处理状态的无状态小部件。
  • 抱歉,我的意思是future: httpController.fetchAlbum()
【解决方案2】:

@Ananda 是正确的,您不需要 futureAlbum 的单独变量;

此外,当您初始化 GetX 类的对象时,您不会这样做

  var httpController = HttpController();

你这样做。

final httpController = Get.put(HttpController());

或者,如果您已经在应用程序的其他地方进行了初始化,您可以找到相同的控制器。

final httpController = Get.find<HttpController>();

当您调用Get.put(...()) 时,即调用onInit 函数。但在你的情况下,你甚至不需要那个。您的 GetX 类可以是这样的。

class HttpController extends GetxController {
  Future<Album> fetchAlbum() async {
    final response = await http
        .get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));

    if (response.statusCode == 200) {
      debugPrint('futureAlbum initialized');
      return Album.fromJson(jsonDecode(response.body));
    } else {
      throw Exception('Failed to load album');
    }
  }
}

您的ViewHttp 可以如下所示。这将在屏幕上显示您的 API 数据。

class ViewHttp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final httpController = Get.put(HttpController());
    return Center(
        child: FutureBuilder<Album>(
      future: httpController.fetchAlbum(),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return Text(snapshot.data!.title);
        } else if (snapshot.hasError) {
          return Text('${snapshot.error}');
        }

        // By default, show a loading spinner.
        return const CircularProgressIndicator();
      },
    ));
  }
}

另外作为一个仅供参考,虽然我一般推荐 GetX,但它在您的 HttpController 课程中没有做任何事情。如果这就是你打算让那个类做的所有事情,那么你可以删除 GetX 部分,按照以前的方式对其进行初始化,并且功能不会改变。

GetX(和大多数其他状态管理解决方案)的一个要点是您始终访问控制器的同一个实例(除非您特别需要一个通常不需要的新实例)以及您存储的任何数据在这种情况下,可以通过Get.find&lt;...&gt;() 从应用程序中的任何位置轻松访问。从那里onInit() 变得超级方便,通常允许所有小部件无状态。

但正如我所说,如果你只是用那个类做一个基本的 API,你就不需要 GetX。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-03
    • 2021-11-17
    • 2021-12-01
    • 2022-07-12
    • 1970-01-01
    • 1970-01-01
    • 2022-07-27
    • 2022-06-19
    相关资源
    最近更新 更多