flutter - 使用 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(),
),
),
]),
);
}
}
抱歉,我没有删除布局代码,所以它使代码块很大提前谢谢。
解决方案
您可以在下面复制粘贴运行完整代码
您可以转换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(),
);
}
}
推荐阅读
- haskell - 如何修复此功能
- javascript - 非法字符。在第 '4' 行位置 '6' JavaScript 错误
- php - 如何在 PHP 中转换字符?
- ruby-on-rails - 在设计/注册控制器上使用 Select2 和 Ajax
- reactjs - Vis.js 分层可视化网络算法变了?
- javascript - 电子和反应;检测电子 api 变化与电子遥控器反应
- r - 数据框中最后 4 行的 sumproduct 是否有 R 函数?
- python - 是python中各种对象的比较
- wpf - BackgroundWorker 执行时出现线程错误
- java - 尝试使用 Integer.parseInt() 将字符串转换为整数时出错