Общие настройки Flutter сохраняют значения, а не отображают

У меня есть список курсов. Пользователь отмечает каждый курс завершенным с помощью флажка в ListTile. Я реализовал общие настройки, поэтому список завершенных курсов сохраняется, когда пользователь закрывает приложение. Значения сохраняются, но когда приложение закрывается (в эмуляторе или через IDE) и снова открывается, пользовательский интерфейс показывает значение как ложное (даже когда Терминал сообщает, что значение истинно). При горячем перезапуске пользовательский интерфейс показывает значение True (что ожидалось с самого начала). Мне не удалось заставить пользовательский интерфейс правильно отображать с помощью кнопок эмулятора или на устройстве.

Как я могу заставить пользовательский интерфейс сразу же правильно отображать значения?

 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,
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
2 104
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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();
          }

Я сделал, результат тот же (задумал Каламбур). Единственный способ показать истинное значение bool в пользовательском интерфейсе - это горячий перезапуск.

Caponigri 06.09.2018 19:50

возможно, вы могли бы вставить весь свой код, чтобы проверить ошибку

diegoveloper 06.09.2018 20:04

Я вставил большую часть кода ... Список курсов длиннее 30, поэтому я просто привел 2 в качестве примеров, для удобства чтения. Я также не вставлял другие страницы, которые не имеют ничего общего с общими настройками или списком курсов.

Caponigri 07.09.2018 17:14

Из-за этого пользовательский интерфейс изначально отображался правильно, но теперь исходное значение bool кажется противоположным тому, что показано? При запуске: все как ожидалось. I / flutter (30162): Ориентация компании Результат: ложь I / flutter (30162): Введение в программу обучения Результат: true I / flutter (30162): Результат настройки домашнего офиса: ложный I / flutter (30162): Результат приветствия пакета : false I / flutter (30162): Термины и определения Результат: false Когда пользователь устанавливает флажок для Company Orientation I / flutter (30162): Company Orientation SET TO false Должно быть установлено значение true. Пользовательский интерфейс отображается как истинный ...

Caponigri 07.09.2018 20:56

похоже, это связано с вашей логикой, если мой ответ работает для вас, отметьте как решенный и создайте другой вопрос.

diegoveloper 07.09.2018 21:01

Другие вопросы по теме