Flutter数组格式API响应获取与UI使用方法及Observable模式咨询
Flutter 数组格式API响应处理与登录逻辑修复
一、当前登录代码的核心错误与修复
你的LoginController.login方法返回的是Future<List<UserLogin>>(异步操作),但在LoginPage的按钮点击事件中直接将其强制转换为List<UserLogin>,这会导致运行时错误。同时代码中还有几个逻辑问题:
- 未处理异步操作的等待过程
- 使用
res != []判断数组非空是错误的,应使用res.isNotEmpty - 未处理API请求的异常(如网络错误、状态码非200)
修复后的按钮点击逻辑
onPressed: () async { final String email = emailController.text; final String pass = pwController.text; try { // 等待异步请求完成 List<UserLogin> res = await LoginController.login(email, pass); if (res.isNotEmpty) { print(res[0].role); if (res[0].role == 'ADMIN') { Navigator.of(context).push(MaterialPageRoute( builder: (_) => homePageAdmin() )); } else { Fluttertoast.showToast( msg: "用户不存在或权限不足", toastLength: Toast.LENGTH_LONG, gravity: ToastGravity.CENTER, timeInSecForIosWeb: 1, backgroundColor: Color.fromARGB(255, 3, 87, 156), textColor: Colors.white, fontSize: 12.0 ); } } else { Fluttertoast.showToast( msg: "登录失败,未获取到用户数据", toastLength: Toast.LENGTH_LONG, gravity: ToastGravity.CENTER, timeInSecForIosWeb: 1, backgroundColor: Color.fromARGB(255, 3, 87, 156), textColor: Colors.white, fontSize: 12.0 ); } } catch (e) { // 捕获请求异常并提示 Fluttertoast.showToast( msg: "登录失败:${e.toString()}", toastLength: Toast.LENGTH_LONG, gravity: ToastGravity.CENTER, timeInSecForIosWeb: 1, backgroundColor: Colors.red, textColor: Colors.white, fontSize: 12.0 ); } }
二、Flutter中获取数组格式API响应并在UI中使用的常用方法
1. Async/Await + setState
适合简单场景,在异步方法中获取数据后调用setState更新UI:
List<UserLogin> userList = []; void fetchData() async { try { userList = await LoginController.login(email, pass); setState(() {}); // 通知UI更新 } catch (e) { // 处理异常 } } // 在UI中直接使用userList if (userList.isNotEmpty) { Text(userList[0].userName); }
2. FutureBuilder
Flutter官方提供的组件,自动管理异步操作的加载、成功、失败状态:
// 在State类中定义Future变量 late Future<List<UserLogin>> _futureUserList; @override void initState() { super.initState(); // 初始化请求(或在点击登录时赋值) _futureUserList = LoginController.login(email, pass); } // 在build中使用FutureBuilder FutureBuilder<List<UserLogin>>( future: _futureUserList, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return CircularProgressIndicator(); // 加载中 } else if (snapshot.hasError) { return Text('请求失败:${snapshot.error}'); // 错误状态 } else if (snapshot.hasData && snapshot.data!.isNotEmpty) { return Text('欢迎 ${snapshot.data![0].userName}'); // 成功状态 } else { return Text('未获取到数据'); } }, )
3. 状态管理库(支持Observable模式)
适合复杂页面或全局状态共享场景,比如使用GetX、Provider等实现Observable模式,自动监听数据变化并更新UI。
三、Observable模式的使用建议
可以使用Observable模式来管理登录状态,以下是GetX实现的示例:
1. 添加GetX依赖
在pubspec.yaml中添加:
dependencies: get: ^4.6.5
2. 创建Observable状态控制器
import 'package:get/get.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'package:AtDocHUB/Model/User.dart'; class LoginStateController extends GetxController { // 用RxList实现Observable数组 RxList<UserLogin> userList = <UserLogin>[].obs; RxBool isLoading = false.obs; RxString errorMsg = ''.obs; Future<void> login(String email, String password) async { isLoading.value = true; errorMsg.value = ''; try { final response = await http.get(Uri.parse( 'http://192.168.0.111:8081/AtdochubJ-3/user/login?useremail=$email&userpassword=$password')); if (response.statusCode == 200) { final parsed = json.decode(response.body).cast<Map<String, dynamic>>(); userList.value = parsed.map<UserLogin>((json) => UserLogin.fromJson(json)).toList(); if (userList.isNotEmpty && userList[0].role == 'ADMIN') { Get.to(() => homePageAdmin()); } else { errorMsg.value = "用户不存在或权限不足"; } } else { throw Exception('请求失败,状态码:${response.statusCode}'); } } catch (e) { errorMsg.value = "登录失败:${e.toString()}"; } finally { isLoading.value = false; } } }
3. 在LoginPage中使用Observable状态
// 在MyCustomFormState中初始化控制器 final LoginStateController loginController = Get.put(LoginStateController()); // 按钮点击事件 onPressed: () { final String email = emailController.text; final String pass = pwController.text; loginController.login(email, pass); } // 在UI中监听状态变化 Obx(() { if (loginController.isLoading.value) { return CircularProgressIndicator(); } else if (loginController.errorMsg.value.isNotEmpty) { return Text( loginController.errorMsg.value, style: TextStyle(color: Colors.red), ); } else { return MaterialButton(/* 原按钮代码 */); } })
内容的提问来源于stack exchange,提问作者Minal Suryawanshi
相关产品推荐
相关产品推荐

