首页 > 解决方案 > 使用 sharedPrefrences 或 JSON 保存用户数据(我的类格式)

问题描述

我刚刚完成了一个学习 Flutter 的课程,上一个项目是一个简单的 Todo-List,关闭应用后任务不能在那里真的很烦人。课程的完整代码在这里

我的代码完全没有区别:

我真的很喜欢提供者和任务类的工作,所以我不想更改它,所以我尝试将数据保存为原样,方法是创建两个列表,一个用于字符串,另一个用于布尔值,将它们取出以保存它们(写),然后读取并将它们放在原来的位置(Read)
理论上是这样的——Task(StringList[index],boolList[index]) 在一个循环内——作为对 Task 类的尊重;当我尝试使用 SharedPreferences 保存时,我制作了一个虚拟代码,导致添加任务不起作用

任何节省的方法都会有所帮助,我的愚蠢想法或任何东西。

sharedPreferences 尝试的“数据”类:

import 'dart:collection';

import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'tasks.dart';
class TaskData extends ChangeNotifier{


 List<Task> _tasks = [];

  UnmodifiableListView<Task> get tasks => UnmodifiableListView(_tasks);

  int get taskCount => _tasks.length;

  String _string;
  String _bool;

  void addTask(String newTaskName) async{
    final task = Task(name: newTaskName);
    _tasks.add(task);

// here is the code

    SharedPreferences sPref = await SharedPreferences.getInstance();
    List<SharedPreferences> sPrefs =[];
    SharedPreferences bPref = await SharedPreferences.getInstance();
    List<SharedPreferences> bPrefs =[];

    for(var item = 0; item <= taskCount; item++){
      //String Preferences
      sPref.setString(_string, tasks[item].name);
      sPrefs.add(sPref);

      //boolean Preferences
      bPref.setBool(_bool,tasks[item].isDone);
      bPrefs.add(bPref);
    }

// code is finished

    notifyListeners();
  }
  void updateTask(Task task){
    task.toggleIsDone();
    notifyListeners();
  }
  void removeTask(Task task){
    _tasks.remove(task);
    notifyListeners();
  }


}

任务类(数据保存在任务数组中的方式)

class Task {
  final String name;
  bool isDone;

  Task({this.name, this.isDone = false});

  void toggleIsDone() {
    isDone = !isDone;
  }
}

现在其他涉及但与 github 代码没有区别的类

添加任务:

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
import 'package:todoey_flutter/components/constants.dart';
import 'package:todoey_flutter/modules/task_data.dart';


class AddTaskScreen extends StatelessWidget {
  final controller = TextEditingController();
  @override
  Widget build(BuildContext context) {
    String userTask;
    return Container(
      color: Color(0xFF737373),
      height: 600,
      child: Container(
        padding: EdgeInsets.all(36.0),
        decoration: kContainerBoxRadius,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Text(
              'Add a Task',
              style: TextStyle(
                  color: Colors.lightBlueAccent,
                  fontSize: 36,
                  fontWeight: FontWeight.w300),
              textAlign: TextAlign.center,
            ),
            Padding(
              padding: EdgeInsets.symmetric(horizontal: 12.0),
              child: TextField(
                style: TextStyle(
                    fontSize: 24.0,
                    fontWeight: FontWeight.w400,
                    color: Colors.lightBlueAccent.shade700),
                onChanged: (inputTask) {
                  userTask = inputTask;
                },
                autofocus: true,
                cursorRadius: Radius.circular(32.0),
                enableSuggestions: true,
                enabled: true,
                expands: false,
                controller: controller,
                textAlign: TextAlign.center,
              ),
            ),
            SizedBox(
              height: 12.0,
            ),
            MaterialButton(
              onPressed: () {
                if (userTask == null) {}
                else {
                  controller.clear();
                  Provider.of<TaskData>(context).addTask(userTask);
                  print(TaskData().taskCount);
                  Navigator.pop(context);
                }
              },
              child: Padding(
                padding: const EdgeInsets.all(12.0),
                child: Text(
                  'ADD',
                  style: TextStyle(
                      fontSize: 22.0,
                      fontWeight: FontWeight.bold,
                      color: Colors.white),
                ),
              ),
              color: Colors.lightBlueAccent,
            ),
          ],
        ),
      ),
    );
  }
}

任务列表:

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
import 'package:todoey_flutter/modules/task_data.dart';
import 'task_tile.dart';

class TaskList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<TaskData>(
      builder: (context, taskData, child) {
        return ListView.builder(
          itemBuilder: (context, index) {
            final task = taskData.tasks[index];
            return TaskTile(
                text: task.name,
                isChecked: task.isDone,
                toggleCheckBoxState: (bool newValue) =>
                    taskData.updateTask(task),
                longPressIdentify: () => taskData.removeTask(task),
            );
          },
          itemCount: taskData.taskCount,
        );
      },
    );
  }
}

TaskTile 是具有一些构造函数的类,其中没有 Task 类或数据

最后来自 main.dart>>(提供者所在)任务屏幕的主要子类:

//a lot of imports mainly task_data and task list and provider and adding tasks class

class TaskScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.lightBlueAccent,
      floatingActionButton: Padding(
        padding: const EdgeInsets.only(bottom: 42.0, right: 36.0),
        child: FloatingActionButton(
            child: Icon(
              Icons.add,
              size: 48.0,
              color: Colors.white,
            ),
            backgroundColor: Colors.lightBlueAccent,
            onPressed: () {
              showModalBottomSheet(
                context: context,
                builder: (context) => AddTaskScreen(),
              );
            }),
      ),
      body: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Container(
              padding: EdgeInsets.only(
                  left: 50.0, top: 120.0, right: 30.0, bottom: 50.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  CircleAvatar(
                    child: Icon(
                      Icons.list,
                      color: Colors.lightBlueAccent,
                      size: 60.0,
                    ),
                    backgroundColor: Colors.white,
                    radius: 40.0,
                  ),
                  SizedBox(
                    height: 36.0,
                  ),
                  Text(
                    'Todoey',
                    style: TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.w800,
                      fontSize: 55.0,
                    ),
                  ),
                  SizedBox(
                    height: 4.0,
                  ),
                  Padding(
                    padding: const EdgeInsets.only(left: 8.0),
                    child: Text(
                      '${Provider.of<TaskData>(context).taskCount} Tasks',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 18.0,
                      ),
                    ),
                  ),
                ],
              ),
            ),
            Expanded(
              child: Container(
                decoration: kContainerBoxRadius,
                child: TaskList(),
              ),
            ),
          ]),
    );
  }
}

抱歉,我没有删除布局代码,所以它使代码块很大提前谢谢。

标签: flutterdartsharedpreferences

解决方案


您可以在下面复制粘贴运行完整代码
您可以转换List<Task>JSON字符串并直接保存此JSON字符串
当您的 APPinit()时,您可以读取此JSON字符串并转换回List<Task>
代码片段

 void main() {
  runApp(MultiProvider(
    providers: [
      ChangeNotifierProvider(
        create: (context) => TaskData()..init(),
      ),
    ],
    child: MyApp(),
  ));
}

 List<Task> taskFromJson(String str) =>
    List<Task>.from(json.decode(str).map((x) => Task.fromJson(x)));

 String taskToJson(List<Task> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
    
 void init() async {
    SharedPreferences sPref = await SharedPreferences.getInstance();
    String jsonTask = sPref.getString("task");
    print(jsonTask);
    if (jsonTask != null) {
      _tasks = taskFromJson(jsonTask);
      notifyListeners();
    }
  }

  void saveToPreference() async {
    SharedPreferences sPref = await SharedPreferences.getInstance();
    sPref.setString("task", taskToJson(_tasks));
  }

  void addTask(String newTaskName) async {
    final task = Task(name: newTaskName);
    _tasks.add(task);
    await saveToPreference();
    notifyListeners();
  }

工作演示

在此处输入图像描述

完整代码

import 'dart:collection';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';

class TaskTile extends StatelessWidget {
  final bool isChecked;
  final String text;
  final Function toggleCheckBoxState;
  final Function longPressIdentify;

  TaskTile(
      {this.isChecked,
      this.text,
      this.toggleCheckBoxState,
      this.longPressIdentify});

  @override
  Widget build(BuildContext context) {
    return ListTile(
      onLongPress: longPressIdentify,
      title: Text(
        text,
        style: TextStyle(
            decoration: isChecked ? TextDecoration.lineThrough : null),
      ),
      trailing: Checkbox(
        activeColor: Colors.lightBlueAccent,
        value: isChecked,
        onChanged: toggleCheckBoxState,
      ),
    );
  }
}

class TaskList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<TaskData>(
      builder: (context, taskData, child) {
        return ListView.builder(
          itemBuilder: (context, index) {
            final task = taskData.tasks[index];
            return TaskTile(
              text: task.name,
              isChecked: task.isDone,
              toggleCheckBoxState: (bool newValue) => taskData.updateTask(task),
              longPressIdentify: () => taskData.removeTask(task),
            );
          },
          itemCount: taskData.taskCount,
        );
      },
    );
  }
}

class AddTaskScreen extends StatefulWidget {
  @override
  _AddTaskScreenState createState() => _AddTaskScreenState();
}

class _AddTaskScreenState extends State<AddTaskScreen> {
  final controller = TextEditingController();

  String userTask;

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Color(0xFF737373),
      height: 600,
      child: Container(
        padding: EdgeInsets.all(36.0),
        //decoration: kContainerBoxRadius,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Text(
              'Add a Task',
              style: TextStyle(
                  color: Colors.lightBlueAccent,
                  fontSize: 36,
                  fontWeight: FontWeight.w300),
              textAlign: TextAlign.center,
            ),
            Padding(
              padding: EdgeInsets.symmetric(horizontal: 12.0),
              child: TextField(
                style: TextStyle(
                    fontSize: 24.0,
                    fontWeight: FontWeight.w400,
                    color: Colors.lightBlueAccent.shade700),
                onChanged: (inputTask) {
                  userTask = inputTask;
                },
                //autofocus: true,
                cursorRadius: Radius.circular(32.0),
                enableSuggestions: true,
                enabled: true,
                expands: false,
                controller: controller,
                textAlign: TextAlign.center,
              ),
            ),
            SizedBox(
              height: 12.0,
            ),
            MaterialButton(
              onPressed: () {
                print(controller.text);
                print("onpressed $userTask");
                if (userTask == null) {
                } else {
                  controller.clear();
                  Provider.of<TaskData>(context, listen: false)
                      .addTask(userTask);
                  print(TaskData().taskCount);
                  Navigator.pop(context);
                }
              },
              child: Padding(
                padding: const EdgeInsets.all(12.0),
                child: Text(
                  'ADD',
                  style: TextStyle(
                      fontSize: 22.0,
                      fontWeight: FontWeight.bold,
                      color: Colors.white),
                ),
              ),
              color: Colors.lightBlueAccent,
            ),
          ],
        ),
      ),
    );
  }
}

List<Task> taskFromJson(String str) =>
    List<Task>.from(json.decode(str).map((x) => Task.fromJson(x)));

String taskToJson(List<Task> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Task {
  final String name;
  bool isDone;

  Task({this.name, this.isDone = false});

  void toggleIsDone() {
    isDone = !isDone;
  }

  factory Task.fromJson(Map<String, dynamic> json) => Task(
        name: json["name"],
        isDone: json["isDone"],
      );

  Map<String, dynamic> toJson() => {
        "name": name,
        "isDone": isDone,
      };
}

class TaskData extends ChangeNotifier {
  List<Task> _tasks = [];

  UnmodifiableListView<Task> get tasks => UnmodifiableListView(_tasks);

  int get taskCount => _tasks.length;

  String _string;
  String _bool;

  void init() async {
    SharedPreferences sPref = await SharedPreferences.getInstance();
    String jsonTask = sPref.getString("task");
    print(jsonTask);
    if (jsonTask != null) {
      _tasks = taskFromJson(jsonTask);
      notifyListeners();
    }
  }

  void saveToPreference() async {
    SharedPreferences sPref = await SharedPreferences.getInstance();
    sPref.setString("task", taskToJson(_tasks));
  }

  void addTask(String newTaskName) async {
    final task = Task(name: newTaskName);
    _tasks.add(task);
    await saveToPreference();
    notifyListeners();
  }

  void updateTask(Task task) async {
    task.toggleIsDone();
    await saveToPreference();
    notifyListeners();
  }

  void removeTask(Task task) async {
    _tasks.remove(task);
    await saveToPreference();
    notifyListeners();
  }
}

class TaskScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.lightBlueAccent,
      floatingActionButton: Padding(
        padding: const EdgeInsets.only(bottom: 42.0, right: 36.0),
        child: FloatingActionButton(
            child: Icon(
              Icons.add,
              size: 48.0,
              color: Colors.white,
            ),
            backgroundColor: Colors.lightBlueAccent,
            onPressed: () {
              showModalBottomSheet(
                context: context,
                builder: (context) => AddTaskScreen(),
              );
            }),
      ),
      body: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Container(
              padding: EdgeInsets.only(
                  left: 50.0, top: 120.0, right: 30.0, bottom: 50.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  CircleAvatar(
                    child: Icon(
                      Icons.list,
                      color: Colors.lightBlueAccent,
                      size: 60.0,
                    ),
                    backgroundColor: Colors.white,
                    radius: 40.0,
                  ),
                  SizedBox(
                    height: 36.0,
                  ),
                  Text(
                    'Todoey',
                    style: TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.w800,
                      fontSize: 55.0,
                    ),
                  ),
                  SizedBox(
                    height: 4.0,
                  ),
                  Padding(
                    padding: const EdgeInsets.only(left: 8.0),
                    child: Text(
                      '${Provider.of<TaskData>(context).taskCount} Tasks',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 18.0,
                      ),
                    ),
                  ),
                ],
              ),
            ),
            Expanded(
              child: Container(
                //decoration: kContainerBoxRadius,
                child: TaskList(),
              ),
            ),
          ]),
    );
  }
}

void main() {
  runApp(MultiProvider(
    providers: [
      ChangeNotifierProvider(
        create: (context) => TaskData()..init(),
      ),
    ],
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: TaskScreen(),
    );
  }
}

推荐阅读