Expected a value of type 'int', but got one of type 'Null'

1.3k views Asked by At

I'm trying to pull data using github repo tree json with dart (flutter). Expected a value of type 'int', but got one of type 'Null'.

        Expanded(
              child: SingleChildScrollView(
                scrollDirection: Axis.vertical,
                child: Container(
                  ..
                  child: getFileList(),
                ),
              ),
            ),

Expanded in scaffold. I'm not sure I'm using snapshot.data.tree correctly. I want to get all file information.

FutureBuilder getFileList() {
    return FutureBuilder<RepoTree>(
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        if (snapshot.hasData) {
          return Center(
              child: Text(
            "File List\n" + snapshot.data.tree,
          ));
        } else if (snapshot.hasError) {
          return Center(
              child: Text("Error in getFileList " + snapshot.error.toString()));
        } else {
          return const Center(
            child: CircularProgressIndicator(),
          );
        }
      },
      future: getResForRepoList(),
    );
  }

  Future<RepoTree> getResForRepoList() async {
    final response = await http.get(Uri.parse(
        'https://api.github.com/repos/satyasashi/todo_basic/git/trees/master?recursive=1')); 

    if (response.statusCode == 200) {
      return RepoTree.fromJson(
          json.decode(response.body));
    } else {
      throw Exception('Exception in getResForRepoList');
    }
  }

My classes

class RepoTree {
  String sha;
  String url;
  List<RepoInside> tree;
  bool truncated;

  RepoTree({
    required this.sha,
    required this.url,
    required this.tree,
    required this.truncated,
  });

  factory RepoTree.fromJson(Map<String, dynamic> json) {
    return RepoTree(
      sha: json["sha"],
      url: json["url"],
      // tree: List<RepoInside>.from(
      //     json["tree"].map((x) => RepoInside.fromJson(x))),
      tree: (json['tree'] ?? [])
          .map((x) => RepoInside.fromJson(x))
          .toList()
          .cast<RepoInside>(),
      truncated: json["truncated"],
    );
  }

  Map<String, dynamic> toJson() => {
        "sha": sha,
        "url": url,
        "tree": List<String>.from(tree.map((x) => x.toJson())),
        "truncated": truncated,
      };
}

class RepoInside {
  String path;
  String mode;
  Type type;
  String sha;
  int size;
  String url;

  RepoInside({
    required this.path,
    required this.mode,
    required this.type,
    required this.sha,
    required this.size,
    required this.url,
  });

  factory RepoInside.fromJson(Map<String, dynamic> json) {
    return RepoInside(
      path: json["path"],
      mode: json["mode"],
      type: typeValues.map[json["type"]]!,
      sha: json["sha"],
      size: json["size"] as int,
      url: json["url"],
    );
  }

  Map<String, dynamic> toJson() => {
        "path": path,
        "mode": mode,
        "type": typeValues.reverse[type],
        "sha": sha,
        "size": size,
        "url": url,
      };
}

enum Type { blob, tree }

final typeValues = EnumValues({"blob": Type.blob, "tree": Type.tree});

class EnumValues<T> {
  Map<String, T> map;
  Map<T, String> reverseMap = {};

  EnumValues(this.map);

  Map<T, String> get reverse {
    if (reverseMap == null) {
      reverseMap = map.map((k, v) => new MapEntry(v, k));
    }
    return reverseMap;
  }
}

I'm having a really hard time on this subject, I would appreciate it if you could explain your answers in detail. Thanks :)

2

There are 2 answers

0
muazzez On BEST ANSWER
Future<List<RepoInside>> fetchRepoInsideTree() async {
  final response = await http.get(Uri.parse(_link));

  if (response.statusCode == 200) {
    List jsonResponse = json.decode(response.body)['tree']; // ADD
    return jsonResponse.map((e) => RepoInside.fromJson(e)).toList();
  } else {
    throw Exception('Failed to load RepoInside from API');
  }
}

And can be used as in FutureBuilder<List<RepoInside>>()

snapshot.data![i].path()

In short, by adding the ['tree'] expression here, we got the list from the json.

0
Ankit Kumar Maurya On

In case if size attribute is null here

  factory RepoInside.fromJson(Map<String, dynamic> json) {
    return RepoInside(
      path: json["path"],
      mode: json["mode"],
      type: typeValues.map[json["type"]]!,
      sha: json["sha"],
      size: json["size"] as int,
      url: json["url"],
    );
  }

You can use null-aware oparator ?? to avoid null to get stored in the size field; You can do it like this

  factory RepoInside.fromJson(Map<String, dynamic> json) {
    return RepoInside(
      path: json["path"],
      mode: json["mode"],
      type: typeValues.map[json["type"]]!,
      sha: json["sha"],
      size: json["size"] ?? 0,
      url: json["url"],
    );
  }

What ?? does? Taking examples Example 1

int i;
i = null ?? 7;
print(i); //prints 7

Example 2

int i;
i = 10 ?? 7;
print(i); //prints 10

?? will assign the value at left if it is not null, otherwise the right one.

NOTE: make sure that json["size"] is int! If not then you can use var size; instead of int size;.