类型 '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;
}
}
这可能可以通过简单的类型转换来解决。我注意到您将 Dio
与 GetConnect
一起使用。这本身没什么问题,但我无法想象你为什么需要两者。
由于您已经在 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
}
我将 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;
}
}
这可能可以通过简单的类型转换来解决。我注意到您将 Dio
与 GetConnect
一起使用。这本身没什么问题,但我无法想象你为什么需要两者。
由于您已经在 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
}