类型 'List<dynamic>' 不是类型 'List<Todo>' 的子类型

type 'List<dynamic>' is not a subtype of type 'List<Todo>'

我将 dio 与 getx 一起使用来获取待办事项数据列表,但我看到了这条消息

type 'List<dynamic>' is not a subtype of type 'List<Todo>'

当我到达这条线时

列表响应Bode = rsp.data['data'];

这一行发生了什么以及如何解决它,谢谢

服务class 已更新并转换为列表,但问题仍然存在

1-控制器的第一个class 2- 第二个用于服务 class

class TodoListController extends GetxController {
  //var lstTask = List<dynamic>.empty(growable: true).obs;
  var items = List<Todo>.empty(growable: true).obs;

  var page = 1.obs;
  var totalRows = 10.obs;
  var isDataProcessing = false.obs;
  var isMoreDataAvailable = true.obs;
  var isSearching = false.obs;
  var isLoading = false.obs;
  var isCompleted = true.obs;

  var errorMsg = ''.obs ;
  var http = new HttpUtils();

  // For Pagination
  ScrollController scrollController = ScrollController();

  @override
  onInit() {
    super.onInit();
    // Fetch Data
    getTodo(page);

  }

  // Fetch Data
   getTodo(var page) {
    try {
      isMoreDataAvailable(false);
      isDataProcessing(true);
      AppServices().getTodo(page).then((resp) {
        isDataProcessing(false);
        resp.forEach(( dynamic json) {
          items.add(Todo.fromJson(json));
        });
        print(resp);
        //items.addAll(resp);
      }, onError: (err) {
        isDataProcessing(false);
        AppServices().showSnackBar("Error", err.toString(), Colors.red);
      });
    } catch (exception) {
      isDataProcessing(false);
      AppServices().showSnackBar("Exception", exception.toString(), Colors.red);
    }
  }

  // Get More data
   getMoreTodo(var page) {
    try {
        AppServices().getTodo(page).then((resp) {
        if (resp.length > 0) {
          isMoreDataAvailable(true);
        } else {
          isMoreDataAvailable(false);
          AppServices().showSnackBar("Message", "No more items", Colors.lightBlueAccent);
        }
        items.addAll(resp);
      }, onError: (err) {
        isMoreDataAvailable(false);
        AppServices().showSnackBar("Error", err.toString(), Colors.red);
      });
    } catch (exception) {
      isMoreDataAvailable(false);
      AppServices().showSnackBar("Exception", exception.toString(), Colors.red);
    }
  }
}

   

class AppServices 扩展了 GetConnect { var http = new HttpUtils();

          // Fetch Data
  Future<List<Todo>> getTodo(var id) async {
    try {
      Response rsp =  await http.get(AppUrl.get_todo, {'current_page': id});
      print(rsp.data['data']);
      if (rsp.data["response_status"] != '400') {
        List<Todo> responseBode = rsp.data['data'].map ((todo) => Todo.fromJson(todo)).toList();
        return responseBode;
      } else {
        return rsp.data["response_message"] ;
      }
    }catch(exception)
    {
      return Future.error(exception.toString());
    }
  }
}

问题是 dynamic 的列表无法自动转换为 Todo 的列表。 您可以像这样转换列表:

 List<Todo> responseBode = rsp.data['data'].map ((todo) => Todo.fromJson(todo)).toList();

然后你可以像这样实现 Todo 命名构造器:

class Todo {
     //Your todo class
     String name;
      Todo.fromJson (data) {
          // conversion here
          name = data["name"] ?? null;
    }
}

这可能可以通过简单的类型转换来解决。我注意到您将 DioGetConnect 一起使用。这本身没什么问题,但我无法想象你为什么需要两者。

由于您已经在 GetX 世界中,这里是使用 GetConnect 时的样子。这就是我可以测试的方式,因为我不确定 HttpUtils 来自哪里。

class AppServices extends GetConnect {
  // var http = new HttpUtils();

  // Fetch Data
  Future<List<Todo>> getTodo(var id) async {
    try {
      Response rsp = await httpClient.get(AppUrl.get_todo, {'current_page': id});
      print(rsp.body['data']);
      if (rsp.statusCode != 400) {
        List<Todo> responseBode = rsp.body['data'] as List<Todo>; // casting type here
        return responseBode;
      } else {
        return rsp.body["response_message"];
      }
    } catch (exception) {
      return Future.error(exception.toString());
    }
  }
}

如果这不起作用

List<Todo> responseBode = rsp.body['data'] as List<Todo>; // casting type here

那么你也可以使用 return Future<List> 代替。

然后这会将上一行变成这个

List responseBode = rsp.body['data'];

GetConnect 为您处理 json 解码,因此在使用它时,您无需再手动执行任何 json 工作。

编辑:在关于在 GetConnect 中向 header 添加身份验证的评论中回答您的问题:

你可以这样做。

final url = 'http://...'
 void _setUrl() {
    httpClient.baseUrl = url;
    httpClient.addRequestModifier((request) {
      request.headers['apikey'] = yourApiKey;
      return request;
    });
  }

之后你可以调用

final response = await httpClient.get(url);

您的密钥将在 url。

那么它 return 是一张普通地图,你可以开始了。

您可以只使用 GetConnect 而不使用 Dio。

您的 AppService 看起来像:

Future<List<Todo>> getTodo(var id) async {
  final response =  await http.get(AppUrl.get_todo, query:{'current_page': id}, decoder: Todo.listFromJson);
  if(response.hasError){
    return Future.error(response.statusText);
   }
  return response.body;
}

您的模型将如下所示:

class Todo {
 String name;
  Todo.fromJson (data) {
      name = data["name"] ?? null;
    }

 static List<Todo> listFromJson(dynamic str) => List<Todo>.from((str as List<dynamic>).map((x) => Todo.fromJson(x)));
}

现在它将直接return Todo 对象列表。

用法可能是这样的(在控制器中):

final todoList = <Todo>[].obs; 

onInit()async{
 ...
 await getTodos();
}

Future<void> getTodos()async{
  try{
     final todos=await appServices.getTodo(1);
     todoList.assignAll(todos);
   } catch (e){
    // handle errors here. eg. show snackbar
   }