【问题标题】:Flutter Shared Preferences saving values, not displayingFlutter Shared Preferences 保存值,不显示
【发布时间】:2019-02-11 23:04:34
【问题描述】:

我有一个课程列表。用户使用 ListTile 上的复选框将每门课程标记为完成。 我实现了共享首选项,因此当用户关闭应用程序时,已完成课程的列表仍然存在。 值正在保存,但是当应用程序关闭(在模拟器中或通过 IDE)并重新打开时,UI 将值显示为 false(即使终端显示值为 True)。 当我热启动时,UI 将值显示为 True(从一开始就预期)。我无法使用模拟器按钮或在设备上正确显示 UI。

如何让 UI 立即正确显示值?

 SharedPreferences prefs;

  void getResult(Course course) async {
    prefs = await SharedPreferences.getInstance();
    results[course.courseResult] = prefs.getBool(course.courseResult) ?? false;
    print('${course.courseTitle} Result: ${results[course.courseResult]}');
    setState(() {
      results[course.courseResult];
      });
  }

  Future<bool> setResult(Course course) async {
    prefs = await SharedPreferences.getInstance();
    print ('${course.courseTitle} SET TO ${results[course.courseResult]}');
    return prefs.setBool(course.courseResult, results[course.courseResult]);
  }

  initState() {
    super.initState();
    getResult(widget.entry);
    }

  Future onChanged(bool value, Course course)  {
    setState(() {
      results[course.courseResult] = value;
    });
    return setResult(course);
  }

这是完整的代码(虽然我确实出于空间目的缩短了列表,并省略了不受此错误影响的页面...)

    import 'package:flutter/material.dart';
import 'main.dart';
import 'CourseList.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:async';
import 'package:url_launcher/url_launcher.dart';
import 'package:intl/intl.dart';



class LearningPlan extends StatefulWidget{
  LearningPlanState createState() => new LearningPlanState();
}

class LearningPlanState extends State<LearningPlan> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: MyAppBar(
        title: Text('Learning Plan'),
      ),
      drawer: MyDrawer(),
      body: ListView.builder(
          itemBuilder: (BuildContext context, int index) =>
              new CourseTile(courseList[index]),
          itemCount: courseList.length,
        ),
    );
  }
}

class CourseTile extends StatefulWidget {
  CourseTile(this.entry);
  final Course entry;
  CourseTileState createState() => new CourseTileState();
}

class CourseTileState extends State<CourseTile> {

//Detail Card

  Future<Null> _launched; // ignore: unused_field

  Future<Null> _launchInWebViewOrVC(String url) async {
    if (await canLaunch(url)) {
      await launch(url, forceSafariVC: false, forceWebView: false);
    } else {
      throw 'Could not launch $url';
    }
  }

  Widget selfDirectedURL(Course course) {
    if (course.courseMethod == 'Self-Directed') {
      return new IconButton(
          icon: Icon(Icons.cloud_download),
          onPressed: () => setState(() {
            _launched = _launchInWebViewOrVC(course.courseURL);
          }),
      );
    } else {
      return new Container();
    }
  }

  Future<Null> courseDetails(Course course) async {
    await showDialog(
        context: context,
        child: new SimpleDialog(
          title: Text(course.courseTitle),
          children: <Widget>[
            Stack(
              children: <Widget>[
                Center(child: Image.asset(course.courseImage,
                  colorBlendMode: BlendMode.lighten,
                  color: fkBlue25,
                  height: 200.0,
                ),
                ),
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text(course.courseDescription),
                ),

              ],
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                selfDirectedURL(course),
                FlatButton(
                  onPressed: (){
                    Navigator.pop(context);
                  },
                  child: Text('OK'),
                ),
              ],
            ),
          ],
        ));
  }

//CheckBox Constructors


  SharedPreferences prefs;

  void getResult(Course course) async {
    prefs = await SharedPreferences.getInstance();
    results[course.courseResult] = prefs.getBool(course.courseResult) ?? false;
    print('${course.courseTitle} Result: ${results[course.courseResult]}');
    setState(() {
      results[course.courseResult];
      });
  }

  Future<bool> setResult(Course course) async {
    prefs = await SharedPreferences.getInstance();
    print ('${course.courseTitle} SET TO ${results[course.courseResult]}');
    return prefs.setBool(course.courseResult, results[course.courseResult]);
  }

  initState() {
    super.initState();
    getResult(widget.entry);
    }

  Future onChanged(bool value, Course course)  async {
    final result = await setResult(course);
    setState(() {
      results[course.courseResult] = value;
    });
    return result;
  }


//Main Tile

  Widget buildTiles(Course course) {
    return Card(
        shape: Border.all(
          color: fkBlue,
        ),
        margin: EdgeInsets.all(16.0),
        elevation: 8.0,
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: ListTile(
            title: Text(course.courseTitle),
            subtitle: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text(course.courseCode),
                Text(course.courseMethod)
              ],
            ),
            leading: SizedBox(
                height: 60.0,
                width: 60.0,
                child: Image.asset(course.courseImage)),
            trailing: Column(
              children: <Widget>[
                Text(results[course.courseResult] ? 'Complete' : 'Incomplete',
            ),
                Checkbox(
                  value: results[course.courseResult],
                  onChanged: (bool value) {
                    onChanged(value, course);
                    if (value == true) {
                      snackBarCompleted(course);
                    } else {
                      snackBarUnCompleted(course);
                    }
                  },
                ),
            ]
          ),
            onTap: () {
              courseDetails(course);
            }
        ),),
    );
  }

  @override
  Widget build(BuildContext context) {
    return buildTiles(widget.entry);
  }

  void snackBarCompleted(course) {
    Scaffold.of(context).showSnackBar(
      SnackBar(content: Text(
          '${course.courseTitle} completed on ${DateFormat.yMd().format(DateTime.now()).toString()}'
      ),
        backgroundColor: fkBlue,
        duration: Duration(seconds: 3),
      ),
    );
  }

  void snackBarUnCompleted(course) {
    Scaffold.of(context).showSnackBar(
      SnackBar(content: Text('${course.courseTitle} no longer marked \"Complete\"'
      ),
        duration: Duration(seconds: 3),
      ),
    );
  }
}


//Learning Schedule Page

class LearningSchedule extends StatelessWidget {

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: MyAppBar(
        title: Text('Schedule'),
      ),
      drawer: MyDrawer(),
      body: ListView.builder(
        itemBuilder: (BuildContext context, int index) =>
        new LearningScheduleBuilder(courseList[index]),
        itemCount: courseList.length,
      ),
    );
  }
}

class LearningScheduleBuilder extends StatelessWidget {
  LearningScheduleBuilder(this.entry);
  final Course entry;

  Widget buildList (Course course) {
    return Text(course.courseTitle,
      style: new TextStyle(color: results[course.courseResult] ? Colors.grey : fkBlue),);
  }

  @override
  Widget build(BuildContext context) {
    return buildList(entry);
  }
}

final List<Course> courseList = <Course>[
  new Course(
    courseTitle: 'Company Orientation',
    coursePreReq: 'N/A',
    courseCode: 'HR',
    courseURL: '',
    courseMethod: 'Facilitator-Led',
    courseImage: 'assets/courseImage/logo.png',
    courseDescription:
        'Company overview; Benefits package and documents; Ethics and Compliance Training, Introduction to learning programs; Computer orientation; Lab tour; Safety training.',
    courseAudience: 'BCAE BCCC ITAE ITCC TCTAE TCTCC PlasmaCC PlasmaAE',
    courseResult: 'result1',
  ),
  new Course(
    courseTitle: 'Intro to Learning Program',
    coursePreReq: 'N/A',
    courseCode: 'Nicole Asma',
    courseURL: '',
    courseMethod: 'Facilitator-Led',
    courseImage: 'assets/courseImage/logo.png',
    courseDescription:
        'Overview of onboarding program; Components of North America University; Support available for all learning units; introduction to Learning and Development Team Overview of WebEx calls.',
    courseAudience: 'BCAE BCCC ITAE ITCC TCTAE TCTCC PlasmaCC PlasmaAE',
    courseResult: 'result2',
  ),


class Course {
  final String courseTitle;
  final String coursePreReq;
  final String courseCode;
  final String courseDescription;
  final String courseImage;
  final String courseMethod;
  final String courseURL;
  final String courseAudience;
  final String courseResult;

  const Course({
    this.courseTitle,
    this.coursePreReq,
    this.courseCode,
    this.courseDescription,
    this.courseImage,
    this.courseMethod,
    this.courseURL,
    this.courseAudience,
    this.courseResult,
  });

  Course.fromMap(Map<String, dynamic> map)
      : courseTitle = map['courseTitle'],
        coursePreReq = map['coursePreReq'],
        courseCode = map['courseCode'],
        courseDescription = map['courseDescription'],
        courseImage = map['roocourseImagem'],
        courseMethod = map['courseMethod'],
        courseURL = map['courseURL'],
        courseAudience = map['courseAudience'],
        courseResult = map['courseResult'];
}

Map results = {
  'result1': false,
  'result2': false,
  'result3': false,
  'result4': false,

【问题讨论】:

    标签: sharedpreferences flutter


    【解决方案1】:

    你能做出这个小小的改变吗? :

    改变这个:

            Future onChanged(bool value, Course course)  {
                setState(() {
                  results[course.courseResult] = value;
                });
                return setResult(course);
              }
    

    到这里:

            Future onChanged(bool value, Course course) async {
                final result = await setResult(course);
                setState(() {
                  results[course.courseResult] = value;
                });
                return result;
              }
    

    更新

    用这个替换你的 initState 方法:

              _onLayoutDone(_){
                    getResult(widget.entry);
              }
    
    
               @override
              void initState() {
                WidgetsBinding.instance.addPostFrameCallback(_onLayoutDone);
                super.initState();
              }
    

    【讨论】:

    • 我做了,结果相同(双关语)。在 UI 中显示真正的 bool 值的唯一方法是热重启。
    • 也许您可以粘贴所有代码以检查错误
    • 我输入了大部分代码...课程列表有 30 多条,所以为了便于阅读,我只输入了 2 个作为示例。我也没有放入与共享偏好或课程列表无关的其他页面。
    • 这确实使 UI 最初显示正确,但现在初始 bool 值似乎与显示的相反?启动时:一切如预期。 I/flutter (30162): Company Orientation 结果: false I/flutter (30162): Intro to Learning Program 结果: true I/flutter (30162): Home Office Setup 结果: false I/flutter (30162): Welcome Packet 结果: false I/flutter (30162): 术语和定义结果: false 当用户点击 Company Orientation I/flutter (30162) 的复选框时: Company Orientation SET TO false 应该设置为 true。 UI 显示为 true...
    • 看起来和你的逻辑有关,如果我的回答对你有用,请标记为已解决并创建另一个问题。
    猜你喜欢
    • 1970-01-01
    • 2019-08-27
    • 2019-08-27
    • 2021-03-29
    • 2020-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-28
    相关资源
    最近更新 更多