You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中SharedPreferences数据无法及时在Widget显示的问题

SharedPreferences数据无法在Widget中及时显示的问题

在Flutter项目中遇到SharedPreferences数据无法在Widget中及时显示的问题:跳转至目标页面后,TextField始终显示默认值,仅重启页面后数据才正常显示。具体场景及代码如下:

1. Provider模型类的SharedPreferences数据获取方法

Future getDataPerson() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
id = prefs.getInt('id') ?? 000;
name = prefs.getString('name') ?? "Фамилия Имя Отчество";
phone = prefs.getString('phone') ?? "3231313";
email = prefs.getString('email') ?? "";
accessToken =  prefs.getString('accessToken') ?? "нет токенааа";
_login = prefs.getString('login') ?? "нет логинааа";
_password = prefs.getString('password') ?? "нет пароляяя";
notifyListeners();
}

2. Provider初始化方式

body: MultiProvider(
    providers: [
      ChangeNotifierProvider<ApiClient>(create: (_)=>ApiClient()),
      ChangeNotifierProvider<FinalModel>(create: (_)=>FinalModel()),
    ],
    child: FinalScreenState(),
  ),

3. FinalScreen的initState调用数据获取

@override
void initState() {
super.initState();
finalModel = Provider.of<FinalModel>(context,listen: false);
getDataPerson();
}
Future getDataPerson() async{
return await finalModel.getDataPerson();
}

4. TextField绑定数据示例(PhoneWidget)

class PhoneWidget extends StatelessWidget {  
Widget build(BuildContext context) {
var finalModel = Provider.of<FinalModel>(context,listen: true);
return Padding(padding:  EdgeInsets.only(top: 10, bottom: 10,right: 
   1,left: 1),
    child: Consumer<FinalModel>(
    builder: (context, model, widget) {
      finalModel.phoneController.text = model.phone;
      return Center(
      child: TextField(
        controller: finalModel.phoneController,
        enabled: false,
        decoration: const InputDecoration(
        labelText: "Телефон",
        contentPadding: EdgeInsets.only(left: 10, top: 10, bottom: 10),
        border: OutlineInputBorder(),
        ),
      ));
    })
   );
  }
}

业务流程:登录后存储数据并跳转

登录成功后将API返回数据存入SharedPreferences,再跳转至FinalScreen:

var statusOne =await apiClient.signIn(_loginEmail1.text, _passwordParol1.text);
Map<String, dynamic> map = jsonDecode(rawJson);
bool status = map['status'];
if (status == true) {
  setDataPerson();
  Navigator.pushReplacementNamed(context, 'final');}

setDataPerson存储方法:

void setDataPerson() async {
final prefs = await SharedPreferences.getInstance();
var statusOne =
    await apiClient.signIn(_loginEmail1.text, _passwordParol1.text);
var rawJson = AuthModel.fromJson(statusOne.data);
await prefs.setInt('id', rawJson.data!.performerId!);
await prefs.setString('name', rawJson.data!.fullName!);
await prefs.setString('phone', rawJson.data!.phone!);
await prefs.setString('accessToken', rawJson.data!.accessToken!);
}

问题核心

  • 跳转后TextField仅显示默认值,无法读取到SharedPreferences中刚存储的最新数据
  • 重启页面后数据显示正常
  • 不想使用listen: true,避免getDataPerson被频繁调用

解决方案

1. 等待SharedPreferences存储完成再跳转

当前登录流程中调用setDataPerson()后立即跳转,但setDataPerson是异步方法,数据尚未写入完成就跳转,导致FinalScreen读取的还是旧数据。修改登录逻辑,等待存储完成再跳转:

if (status == true) {
  await setDataPerson(); // 等待数据写入完成
  Navigator.pushReplacementNamed(context, 'final');
}

2. 优化Provider与Widget的绑定逻辑

不要在Consumer的builder中直接修改controller文本,可在模型类中同步controller与数据:

class FinalModel extends ChangeNotifier {
  String phone = "3231313";
  late TextEditingController phoneController;

  FinalModel() {
    phoneController = TextEditingController(text: phone);
  }

  Future getDataPerson() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    phone = prefs.getString('phone') ?? "3231313";
    // 同步controller文本
    phoneController.text = phone;
    notifyListeners();
  }
}

Widget中直接使用模型的controller即可,无需在builder中修改:

class PhoneWidget extends StatelessWidget {  
Widget build(BuildContext context) {
return Consumer<FinalModel>(
    builder: (context, model, widget) {
      return Padding(
        padding: EdgeInsets.only(top: 10, bottom: 10, right: 1, left: 1),
        child: Center(
          child: TextField(
            controller: model.phoneController,
            enabled: false,
            decoration: const InputDecoration(
              labelText: "Телефон",
              contentPadding: EdgeInsets.only(left: 10, top: 10, bottom: 10),
              border: OutlineInputBorder(),
            ),
          ),
        ),
      );
    })
   );
  }
}

3. 确保数据加载完成后再渲染Widget

在FinalScreen中添加加载状态,等待getDataPerson执行完成后再显示页面内容,避免读取未更新的数据:

class FinalScreenState extends StatefulWidget {
  @override
  _FinalScreenStateState createState() => _FinalScreenStateState();
}

class _FinalScreenStateState extends State<FinalScreenState> {
  late FinalModel finalModel;
  bool _isLoading = true;

  @override
  void initState() {
    super.initState();
    finalModel = Provider.of<FinalModel>(context, listen: false);
    _loadData();
  }

  Future<void> _loadData() async {
    await finalModel.getDataPerson();
    setState(() {
      _isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (_isLoading) {
      return Center(child: CircularProgressIndicator());
    }
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        IdWidget(),
        NameWidget(),
        PhoneWidget(),
        EmailWidget(),
      ],
    );
  }
}

内容的提问来源于stack exchange,提问作者N.E.K

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 18:35:20