为何FutureBuilder无法获取Provider中GetLoginData方法的返回值?
问题解决方法
问题根源
- 原代码在
build方法中重复调用GetLoginData(),每次都会创建新的Future,导致FutureBuilder反复执行异步请求,引发不必要的资源消耗和状态异常。 GetLoginData()没有缓存登录状态,每次调用都重新读取SharedPreferences,效率低下;且build方法无法直接await异步方法,无法直接获取返回值。
重构方案
1. 改造TodoList类,缓存登录状态并提供初始化方法
将异步读取SharedPreferences的逻辑移到初始化方法中,把登录状态缓存为类成员变量,通过notifyListeners()通知UI更新:
class TodoList extends ChangeNotifier { bool _isLoggedIn = false; bool _isInitialized = false; // 标记是否完成初始化 // 初始化时加载登录状态 Future<void> initLoginState() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); _isLoggedIn = prefs.getBool('data') ?? false; _isInitialized = true; notifyListeners(); } // 获取缓存的登录状态 bool get isLoggedIn => _isLoggedIn; // 获取初始化状态 bool get isInitialized => _isInitialized; // 可选:更新登录状态的方法(登录/登出时调用) Future<void> updateLoginState(bool value) async { final SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.setBool('data', value); _isLoggedIn = value; notifyListeners(); } }
2. 修改State类,在初始化阶段加载状态
在initState中调用Provider的初始化方法,UI直接监听缓存的状态,无需再使用FutureBuilder:
class _CheckState extends State<Check> { @override void initState() { super.initState(); // 初始化登录状态,listen: false表示不监听状态变化 Provider.of<TodoList>(context, listen: false).initLoginState(); } @override Widget build(BuildContext context) { final todoList = Provider.of<TodoList>(context); // 未完成初始化时显示加载指示器 if (!todoList.isInitialized) { return const Center(child: CircularProgressIndicator()); } // 根据缓存的状态跳转页面 return todoList.isLoggedIn ? const Main() : const Login(); } }
额外说明
- 原代码中
print(x.GetLoginData().toString())打印的是Future实例而非布尔值,因为异步方法返回的是Future,必须通过await才能获取实际返回值,但build方法不能标记为async,因此这种写法无效。 - 缓存状态的方式能避免重复读取
SharedPreferences,提升性能,同时保证UI状态与持久化数据一致。
内容的提问来源于stack exchange,提问作者Aman Nafiz
相关产品推荐
相关产品推荐

