0

Below is how my json looks like

{
    "data": {
        "id": 2,
        "email": "floki@mail.com",
        "first_name": "Valjakudze",
        "last_name": "shipment",
        "avatar": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7e/Circle-icons-profile.svg/1024px-Circle-icons-profile.svg.png"
    }
}

I am using Dio and below are my two classes for the responses

Response Class


import 'package:json_annotation/json_annotation.dart';
import 'package:json_crud/classes/user.dart';
part 'user_response.g.dart';

@JsonSerializable()
class UserResponse{

  @JsonKey(name: "data")
  User? user;

  UserResponse();

  factory UserResponse.fromJson(Map<String, dynamic> json) => _$UserResponseFromJson(json);
  Map<String, dynamic> toJson() => _$UserResponseToJson(this);

}

Below is my UserClass


import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';

@JsonSerializable()
class User{

  @JsonKey(name: "id")
  late int id;

  @JsonKey(name: "email")
  late String email;

  @JsonKey(name: "first_name")
  late String firstName;

  @JsonKey(name: "last_name")
  late String lastName;

  @JsonKey(name: "avatar")
  late String avatar;

  User();

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);

}

Below is my UserProfileScreen where i am supposed to set text

import 'dart:developer';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:json_crud/classes/user.dart';
import 'package:json_crud/classes/user_response.dart';
import 'package:json_crud/http_service.dart';

class UserProfile extends StatefulWidget {

  const UserProfile({Key? key}) : super(key: key);

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

class _UserProfileState extends State<UserProfile> {

  HttpService? httpService;

  UserResponse? userResponse;

  User? user;

  bool isLoading = false;

  Future getUser () async {

    Response response;

    try {
      log("TryCatchCalled");

      response = await httpService!.getRequest("/b/BGT5");

      if(response.statusCode == 200){

        setState(() {

          userResponse = UserResponse.fromJson(response.data);

          user = userResponse!.user;

          log("ResponseStatusCode200 ${response.statusCode}");

        });

      }else{
        log("ResponseStatusCode ${response.statusCode}");
      }
    } on Exception catch (e) {
      isLoading = false;
      log("GetUserResponseException ${e.toString()}");
    }
  }

  @override
  void initState() {

    httpService = HttpService();
    userResponse = UserResponse();
    user = User();

    getUser();

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("User Profile"),
      ),
      body: isLoading
          ? const Center(child: CircularProgressIndicator())
          :  Container(
        width: double.infinity,
        child: Column(
          children: [
            Image.network(user!.avatar),
            Container(height: 16,),
            Text("Hello, ${user!.firstName} ${user!.lastName}")
          ],
        ),
      ),
    );
  }
}

I am getting LateInitializationError: Field 'avatar' has not been initialized error

Below is what i have tried by changing my user class


import 'package:json_annotation/json_annotation.dart';


part 'user.g.dart';

@JsonSerializable()
class User{

  @JsonKey(name: "id")
  int? id;

  @JsonKey(name: "email")
  String? email;

  @JsonKey(name: "first_name")
  String? firstName;

  @JsonKey(name: "last_name")
  String? lastName;

  @JsonKey(name: "avatar")
  String? avatar;

  User();

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);

}

But when i do the above when i change class variables from late i get a new error Error: The argument type 'String?' can't be assigned to the parameter type 'String' because 'String?' is nullable and 'String' isn't. Image.network(user!.avatar),

below is the full error log

======== Exception caught by widgets library =======================================================
The following LateError was thrown building UserProfile(dirty, state: _UserProfileState#c6357):
LateInitializationError: Field 'avatar' has not been initialized.

The relevant error-causing widget was: 
  UserProfile UserProfile:file:///C:/Users/Emman/AndroidStudioProjects/json_crud/lib/main.dart:28:19
When the exception was thrown, this was the stack: 
#0      User.avatar (package:json_crud/classes/user.dart)
#1      _UserProfileState.build (package:json_crud/screens/user_profile.dart:81:19)
#2      StatefulElement.build (package:flutter/src/widgets/framework.dart:4705:27)
#3      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4588:15)
#4      StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4763:11)
#5      Element.rebuild (package:flutter/src/widgets/framework.dart:4311:5)
#6      ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4566:5)
#7      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4754:11)
#8      ComponentElement.mount (package:flutter/src/widgets/framework.dart:4561:5)
...     Normal element mounting (169 frames)
#177    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3631:14)
#178    MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6261:36)
#179    MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6272:32)
...     Normal element mounting (391 frames)
#570    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3631:14)
#571    Element.updateChild (package:flutter/src/widgets/framework.dart:3383:18)
#572    RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1198:16)
#573    RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1167:5)
#574    RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:1112:18)
#575    BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2531:19)
#576    RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1111:13)
#577    WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:944:7)
#578    WidgetsBinding.scheduleAttachRootWidget.<anonymous closure> (package:flutter/src/widgets/binding.dart:924:7)
(elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)
====================================================================================================

how can i solve this

Emmanuel Njorodongo
  • 1,004
  • 17
  • 35
  • you just need to handle the case where the avatar is null, cause it seems like it doesn't always have a value in your response. i.e `user!.avatar != null ? Image.network(user!.avatar) : Image.asset("assets/default_avatar.png)` – omar hatem Jan 09 '22 at 20:14
  • @omarhatem i am still getting the same error – Emmanuel Njorodongo Jan 09 '22 at 21:36

2 Answers2

0

It says where the error after your changes comes from right there:

type 'String?' is nullable and 'String' isn't.

so when you type your variable firstName like this: String? firstName; then the compiler is totally happy with firstName = null.

When you type it like String firstName; then its type "String" _prevents it from ever becoming null.

Maybe you have somewhere typed what should be a String? (or fetched by an if) as String, f.e. in

factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);?

user3249027
  • 545
  • 5
  • 17
0

You are calling getUser in your init method, but since it it's async and returns a Future, you need to await it. Otherwise your code will not have completed when your build method gets called and your variables are still set to their default values (which means your late variables have never been initialized on those instances and you get the error you see).

As you cannot use the await keyword in a method that is not itself async (and initState is not), you need to find a way around that. The most common is using a FutureBuilder widget.

You can find a good example of the general setup here: What is a Future and how do I use it?

nvoigt
  • 75,013
  • 26
  • 93
  • 142