Flutter Shared Preferences сохраняет значения, не отображая - PullRequest
0 голосов
/ 06 сентября 2018

У меня есть список курсов. Пользователь помечает каждый курс как завершенный, используя флажок на ListTile. Я реализовал «Общие настройки», поэтому список завершенных курсов сохраняется, когда пользователь закрывает приложение. Значения сохраняются, но когда приложение закрывается (в эмуляторе или через IDE) и открывается снова, пользовательский интерфейс отображает значение как ложное (даже когда терминал говорит, что значение равно True). При горячем перезапуске пользовательский интерфейс показывает значение как 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,

1 Ответ

0 голосов
/ 06 сентября 2018

Не могли бы вы сделать это небольшое изменение? :

Изменить это:

        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;
          }

UPDATE

Замените ваш initState метод следующим:

          _onLayoutDone(_){
                getResult(widget.entry);
          }


           @override
          void initState() {
            WidgetsBinding.instance.addPostFrameCallback(_onLayoutDone);
            super.initState();
          }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...