I am trying to fetch data Using Github API and display it in flutter app but in FutureBuilder snapshot.hasData shows its null and executes snapshot.hasError. I want to display name of repositories from github in a ListView
Can you u help to understand and correct the error.
Here is the code :
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class Repo {
String name;
String htmlUrl;
//int stargazersCount;
String description;
Repo(
{required this.name,
required this.htmlUrl,
//required this.stargazersCount,
required this.description}
);
factory Repo.fromJson(Map<String, dynamic> json) {
return Repo(
name: json['name'],
htmlUrl: json['html_url'],
//stargazersCount: json['stargazers_count'],
description: json['description'],
);
}
}
class All {
List<Repo> repos;
All({required this.repos});
factory All.fromJson(List<dynamic> json) {
// ignore: prefer_collection_literals
List<Repo> repos = List<Repo>.empty(growable: true);
repos = json.map((r) => Repo.fromJson(r)).toList();
print(repos);
return All(repos: repos);
}
}
Future<All> fetchRepos() async {
final response =
await http.get(Uri.parse('https://api.github.com/users/freeCodeCamp/repos'));
if (response.statusCode == 200) {
//print(response.body);
return All.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to Fetch repos!');
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late Future<All> futureRepo;
@override
void initState() {
super.initState();
futureRepo=fetchRepos();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Github Repo List'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: FutureBuilder<All>(
future: futureRepo,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Repo> repos = List<Repo>.empty(growable: true);
for (int i = 0; i < snapshot.data!.repos.length; i ) {
repos.add(
Repo(
name: snapshot.data!.repos[i].name,
htmlUrl: snapshot.data!.repos[i].htmlUrl,
// stargazersCount:
// snapshot.data!.repos[i].stargazersCount,
description: snapshot.data!.repos[i].htmlUrl,
),
);
}
return ListView(
children: repos.map((r) => Card(
child: Column(
children: [
Text(r.name),
Text(r.description),
Text(r.htmlUrl),
//Text(r.stargazersCount.toString())
],
),
)).toList(),
);
} else if (snapshot.hasError) {
print(snapshot.error);
return const Center(
child: Text('Error'),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
)
);
}
}
while executing snapshot.error it displays the bellow error:
Expected a value of type 'String', but got one of type 'Null'
CodePudding user response:
- The Repo data model is built wrong. They should use Null safe
class Repo {
String? name;
String? htmlUrl;
//int stargazersCount;
String? description;
Repo(this.name, this.htmlUrl, this.description);
factory Repo.fromJson(Map<String, dynamic> json) {
return Repo(
json['name'],
json['html_url'],
//stargazersCount: json['stargazers_count'],
json['description'],
);
}
}
return ListView(
children: repos
.map((r) => Card(
child: Column(
children: [
Text(r.name ?? ''),
Text(r.description ?? ''),
Text(r.htmlUrl ?? ''),
//Text(r.stargazersCount.toString())
],
),
))
.toList(),
);