admin管理员组

文章数量:1406182

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
Add a comment  | 

2 Answers 2

Reset to default 0

Try 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'] ?? [],
    );
  }
}

本文标签: jsonMapltStringdynamicgt is not a subtype of type Listltdynamicgt in cast typeStack Overflow