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

Flutter应用中SharedPreferences存储内容首次加载不显示的解决方法

问题解决:首次加载项目详情页不显示SharedPreferences数据

问题原因

核心问题是异步获取SharedPreferences数据后,没有通知Flutter框架触发UI重建:

  • _fetchData是异步方法,在initState中调用后,数据加载完成时组件已经完成首次渲染,此时给pname/pdesc/pdue赋值不会自动更新UI
  • 热重载时,数据已经提前加载到变量中,所以渲染时能直接显示值

解决方案

在异步获取数据完成后,调用setState(() {})通知框架更新状态,触发组件重建。

修正后的完整代码

import 'package:flutter/material.dart';
import 'package:mne/Actual%20Tasks/activity_widget.dart';
import 'package:mne/UserTasks/task_widget.dart';
import 'package:shared_preferences/shared_preferences.dart';

class ProjectTask extends StatefulWidget {
  const ProjectTask({Key key}) : super(key: key);

  @override
  State<ProjectTask> createState() => _ProjectTaskState();
}

class _ProjectTaskState extends State<ProjectTask> {
  String pname;
  String pdesc;
  String pdue;

  @override
  void initState() {
    super.initState();
    _fetchData();
  }

  Future<Null> _fetchData() async {
    // 注:WidgetsFlutterBinding.ensureInitialized()在initState中不需要,此时Flutter绑定已初始化
    SharedPreferences localStorage = await SharedPreferences.getInstance();
    // 获取数据后更新状态
    setState(() {
      pname = localStorage.getString('project_name');
      pdesc = localStorage.getString('project_desc');
      pdue = localStorage.getString('project_due');
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          iconTheme: const IconThemeData(color: Colors.black),
          backgroundColor: Colors.white,
          automaticallyImplyLeading: true,
          centerTitle: true,
          title: const Text('Project Details',
              style: TextStyle(color: Colors.black))),
      body: SingleChildScrollView(
        child: Column(children: [
          Container(height: 10, color: Colors.transparent),
          // for image
          Container(
            width: 330,
            child: Image.asset('assets/images/projectbanner.png'),
          ),
          //for project name
          Container(
              padding: const EdgeInsets.only(bottom: 25, top: 15),
              child: Row(children: [
                Container(
                  padding: const EdgeInsets.only(left: 20, right: 145),
                  child: Text(pname ?? '',
                      style: const TextStyle(
                          color: Colors.black,
                          fontWeight: FontWeight.bold,
                          fontSize: 16)),
                ),
                Container(
                    padding: const EdgeInsets.only(right: 10, top: 8),
                    child: const Icon(Icons.calendar_month_outlined)),
                RichText(
                    text: TextSpan(children: [
                  const TextSpan(
                      text: 'Due: ',
                      style: TextStyle(
                          fontSize: 12,
                          fontWeight: FontWeight.bold,
                          color: Colors.black)),
                  TextSpan(
                      text: pdue ?? '',
                      style: const TextStyle(fontSize: 12, color: Colors.black))
                ])),
              ])),
          // for description title
          Container(
              alignment: Alignment.centerLeft,
              padding: const EdgeInsets.only(left: 20, bottom: 20),
              child: const Text('Description',
                  style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16))),
          // for actual desc
          Container(
              padding: const EdgeInsets.only(left: 20),
              alignment: Alignment.centerLeft,
              child: Text(
                pdesc ?? '',
                style: const TextStyle(color: Colors.grey),
              )),
          // for task title
          Container(
              padding: const EdgeInsets.only(left: 20, top: 20, bottom: 20),
              alignment: Alignment.centerLeft,
              child: const Text('Tasks',
                  style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16))),
          // for task widget
          Container(height: 630, child: const ActivityWidget()),
        ]),
      ),
    );
  }
}

优化建议(可选)

可以使用FutureBuilder替代手动管理异步状态,代码更简洁且符合Flutter最佳实践:

// 替换原有的变量和initState、_fetchData方法
@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(/* 保持原代码不变 */),
    body: FutureBuilder<SharedPreferences>(
      future: SharedPreferences.getInstance(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          // 数据加载中显示占位符
          return const Center(child: CircularProgressIndicator());
        }
        final localStorage = snapshot.data!;
        final pname = localStorage.getString('project_name');
        final pdesc = localStorage.getString('project_desc');
        final pdue = localStorage.getString('project_due');
        
        // 原有的SingleChildScrollView内容
        return SingleChildScrollView(
          child: Column(/* 保持原代码结构,使用上面的pname/pdesc/pdue变量 */),
        );
      },
    ),
  );
}

效果说明

  • 首次加载问题状态:页面仅显示顶部图片、"Description"和"Tasks"标题,项目名称、截止日期、描述内容均为空
  • 修复后效果:页面加载时会自动获取数据并更新UI,直接显示完整的项目详情信息

内容的提问来源于stack exchange,提问作者clio

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 17:35:24