I want to send a data request to an API and get data from it via the http package and then decode it using dart convert library I searched for ways to implement it and found this documentation provided by flutter team [here][1] but of course I edited it to serve me here is the code
the backend part :
Future<List<Photo>> fetchPhotos(http.Client client) async {
final response = await client.get(
Uri.parse('Endpoint(hidden)'),
);
// Use the compute function to run parsePhotos in a separate isolate.
return await compute(parsePhotos, response.body);
}
List<Photo> parsePhotos(String responseBody) {
final parsed =
(jsonDecode(responseBody) as List).cast<Map<String, dynamic>>();
return parsed.map<Photo>((json) => Photo.fromJson(json)).toList();
}
class Photo {
final bool canLogin;
final bool canRegister;
// final String id;
// final String name;
final List<dynamic> activities;
const Photo({
required this.canLogin,
required this.canRegister,
required this.activities,
});
factory Photo.fromJson(Map<String, dynamic> json) {
return Photo(
canLogin: json['canLogin'] as bool,
canRegister: json['canRegister'] as bool,
activities: json['activities'] as List<dynamic>,
);
}
}
the UI :
class Test extends StatefulWidget {
const Test({super.key, required this.title});
final String title;
@override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
late Future<List<Photo>> getData;
@override
void initState() {
getData = fetchPhotos(http.Client());
super.initState();
}
@override
void dispose() {
getData = fetchPhotos(http.Client());
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('data'),
backgroundColor: Colors.blue,
),
floatingActionButton: TextButton(
onPressed: () {
setState(() {});
},
child: const Text('Reload')),
body: FutureBuilder<List<Photo>>(
future: getData,
builder: (context, snapshot) {
if (snapshot.hasData) {
devtools.log('has data');
return PhotosList(photos: snapshot.data);
} else if (snapshot.hasError) {
devtools.log('has error');
return Text(snapshot.error.toString());
}
return const CircularProgressIndicator();
},
),
);
}
}
class PhotosList extends StatelessWidget {
const PhotosList({super.key, required this.photos});
final List<Photo>? photos;
@override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
itemCount: photos!.length,
itemBuilder: (context, index) {
return Text(photos![index].activities.toString());
},
);
}
}
I am familiar with the error I used to figure it out but this time its my first time dealing with API thing so I couldn't solve it for 2 days which is unusual for me and frustrating [1]: /cookbook/networking/background-parsing#notes-on-working-with-isolates
I want to send a data request to an API and get data from it via the http package and then decode it using dart convert library I searched for ways to implement it and found this documentation provided by flutter team [here][1] but of course I edited it to serve me here is the code
the backend part :
Future<List<Photo>> fetchPhotos(http.Client client) async {
final response = await client.get(
Uri.parse('Endpoint(hidden)'),
);
// Use the compute function to run parsePhotos in a separate isolate.
return await compute(parsePhotos, response.body);
}
List<Photo> parsePhotos(String responseBody) {
final parsed =
(jsonDecode(responseBody) as List).cast<Map<String, dynamic>>();
return parsed.map<Photo>((json) => Photo.fromJson(json)).toList();
}
class Photo {
final bool canLogin;
final bool canRegister;
// final String id;
// final String name;
final List<dynamic> activities;
const Photo({
required this.canLogin,
required this.canRegister,
required this.activities,
});
factory Photo.fromJson(Map<String, dynamic> json) {
return Photo(
canLogin: json['canLogin'] as bool,
canRegister: json['canRegister'] as bool,
activities: json['activities'] as List<dynamic>,
);
}
}
the UI :
class Test extends StatefulWidget {
const Test({super.key, required this.title});
final String title;
@override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
late Future<List<Photo>> getData;
@override
void initState() {
getData = fetchPhotos(http.Client());
super.initState();
}
@override
void dispose() {
getData = fetchPhotos(http.Client());
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('data'),
backgroundColor: Colors.blue,
),
floatingActionButton: TextButton(
onPressed: () {
setState(() {});
},
child: const Text('Reload')),
body: FutureBuilder<List<Photo>>(
future: getData,
builder: (context, snapshot) {
if (snapshot.hasData) {
devtools.log('has data');
return PhotosList(photos: snapshot.data);
} else if (snapshot.hasError) {
devtools.log('has error');
return Text(snapshot.error.toString());
}
return const CircularProgressIndicator();
},
),
);
}
}
class PhotosList extends StatelessWidget {
const PhotosList({super.key, required this.photos});
final List<Photo>? photos;
@override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
itemCount: photos!.length,
itemBuilder: (context, index) {
return Text(photos![index].activities.toString());
},
);
}
}
I am familiar with the error I used to figure it out but this time its my first time dealing with API thing so I couldn't solve it for 2 days which is unusual for me and frustrating [1]: https://docs.flutter.dev/cookbook/networking/background-parsing#notes-on-working-with-isolates
Share Improve this question edited Mar 6 at 15:18 VLAZ 29.2k9 gold badges63 silver badges84 bronze badges asked Mar 6 at 14:44 Abdlrhman BashirAbdlrhman Bashir 154 bronze badges 1- Can we see a print of the response from the api – Nnamani Daniel Commented Mar 7 at 2:04
2 Answers
Reset to default 0Try to change like this in your parsePhotos()
:
final parsed = jsonDecode(responseBody) as Map<String, dynamic>;
Maybe your endpoint is returning a json object, not a list. You can find this by checking the first character of the json response. If it's starting with {
, it's an object, so the return of jsonDecode()
would be Map<String, dynamic>
.
In Flutter's example, it was json list because the json response is starting with [
.
The endpoint in Flutter's example: https://jsonplaceholder.typicode/photos
beckend change the Replace with actual API endpoint
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/foundation.dart';
Future<List<Photo>> fetchPhotos() async {
final response = await http.get(
Uri.parse('YOUR_API_ENDPOINT'),
);
if (response.statusCode == 200) {
return compute(parsePhotos, response.body);
} else {
throw Exception('Failed to load data');
}
}
List<Photo> parsePhotos(String responseBody) {
final parsed = jsonDecode(responseBody) as List;
return parsed.map<Photo>((json) => Photo.fromJson(json)).toList();
}
class Photo {
final bool canLogin;
final bool canRegister;
final List<dynamic> activities;
const Photo({
required this.canLogin,
required this.canRegister,
required this.activities,
});
factory Photo.fromJson(Map<String, dynamic> json) {
return Photo(
canLogin: json['canLogin'] as bool? ?? false,
canRegister: json['canRegister'] as bool? ?? false,
activities: json['activities'] ?? [],
);
}
}
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744968646a4603835.html
评论列表(0条)