我建议一般阅读有关 json 序列化的内容,因为无论哪种方式您都需要了解它.这是一个很好的起点和这是另一篇关于它的好文章.说了这么多,也可以在没有 json 的情况下完成,将您的任务转换为 Map(无论如何 json 序列化所做的事情)并将其存储到映射列表中.我将向您展示一个不使用 json 手动执行此操作的示例.但是,再次强调,最好花点时间学习它.此示例将使用 Get Storage,这与 SharedPreferences 类似但更容易,因为您不需要不同数据类型的不同方法,只需read和write.我不知道您是如何在应用中添加任务的,但这只是存储 Task 对象列表的一个基本示例.任何不涉及在线存储的解决方案都需要在本地存储,并在应用启动时从存储中检索.假设这里是您的 Task 对象.class 任务 {最终字符串名称;最终字符串描述;任务({this.name, this.description});}在运行你的应用之前把它放在你的 main 方法中await GetStorage.init();您需要将 async 添加到 main 中,所以如果您不熟悉它的工作原理,它看起来像这样.void main() async {等待 GetStorage.init();运行应用程序(我的应用程序());}通常我永远不会在有状态小部件中执行所有这些逻辑,而是实现一个状态管理解决方案并在 UI 之外的类中执行它,但这是一个完全不同的讨论.我还建议您查看 GetX、Riverpod 或 Provider,阅读有关它们的信息,看看哪一个最容易让您印象深刻.GetX 赢得了我对简单性和功能性的投票.但由于您刚刚开始,我将省略这部分内容,暂时将所有这些功能放在 UI 页面中.此外,它不仅可以在应用程序关闭时存储(也可以这样做),而且可以更轻松地在列表发生更改时随时存储.这是一个页面,其中包含一些用于添加、清除和打印存储的按钮,因此您可以在应用重启后准确查看列表中的内容.如果您了解这里发生了什么,您应该能够在您的应用程序中执行此操作,或者研究 json 并以这种方式执行此操作.无论哪种方式,您都需要了解 Maps 以及本地存储如何与任何可用解决方案配合使用.class StorageDemo 扩展 StatefulWidget {@覆盖_StorageDemoState createState() =>_StorageDemoState();}class _StorageDemoState 扩展 State{列表_tasks = [];最后一个框 = GetStorage();//地图列表存储在这里//用于存储地图/restoreTask 函数的单独列表//在initState上从这个列表中填充_tasks列表存储列表 = [];void addAndStoreTask(Task task) {_tasks.add(task);最终存储映射 = {};//添加到存储中的临时映射最终索引 = _tasks.length;//对于唯一的映射键最终 nameKey = 'name$index';final descriptionKey = 'description$index';//将任务属性添加到临时映射storageMap[nameKey] = task.name;storageMap[descriptionKey] = task.description;storageList.add(storageMap);//将临时映射添加到 storageListbox.write('tasks', storageList);//将地图列表添加到存储}无效恢复任务(){storageList = box.read('tasks');//从存储初始化列表String nameKey, descriptionKey;//遍历存储列表以从映射中解析出任务对象for (int i = 0; i < storageList.length; i++) {最终地图 = storageList[i];//检索键的索引占索引从 0 开始最终索引 = i + 1;nameKey = 'name$index';descriptionKey = '描述$索引';//从存储中重新创建任务对象最终任务=任务(名称:地图[名称密钥],描述:地图[描述密钥]);_tasks.add(task);//将任务添加回您的正常任务列表}}//遍历您的列表以查看里面的内容无效打印任务(){for (int i = 0; i < _tasks.length; i++) {调试打印('任务 ${i + 1} 名称 ${_tasks[i].name} 描述:${_tasks[i].description}');}}void clearTasks() {_tasks.clear();storageList.clear();box.erase();}@覆盖无效的初始化状态(){super.initState();恢复任务();//从存储在 initState 中恢复列表}@覆盖小部件构建(BuildContext 上下文){返回脚手架(正文:列(mainAxisAlignment: MainAxisAlignment.center,孩子们: [中心(孩子:容器(),),文本按钮(按下: () {最终任务=任务(描述:'测试描述',名称:'测试名称');addAndStoreTask(task);},孩子:文本('添加任务'),),文本按钮(按下: () {打印任务();},孩子:文本('打印存储'),),文本按钮(按下: () {清除任务();},孩子:文本('清除任务'),),],),);}}The situation:I'm very new to Flutter and mobile development, thus I don't know much about Dart; And I've read some solutions from people with similar problems but didn't manage to work these solutions to my own thing.The problem:I have a to-do app that has 2 Lists of Objects, and I want to store those Lists for whenever the user re-open the app.I know its simple stuff but I feel like I'm storming towards this problem due to the lack of experience... And so I decided to come asking for some light.What I've tried:I have come across different solutions for this problem and all of them seemed way too complex to this case (compared to what I'm used to do when saving lists to the archive), including: encoding the list to a map and converting to a string before using SharedPreferences, using SQlite database (every tutorial I've come across made me feel like I'd be using a war tank to kill an ant, I'd say the same about firebase).Structure of the problem:ToDo screen with a ListView.builder calling 2 arrays: ongoing tasks and done tasks each of which I want to write to the phone whenever the user makes a change. IDK if I should only try to save those arrays from within the class from which they belong by calling some packages methods, or if I should try to store the entire application if such thing is possible.Conclusion:Is there a way to solve this in a simple way or I should use something robust like firebase just for that? even though I'm not used to work with firestore, and so I'm in the dark not knowing how to apply such thing to save data.How my lists are structured:List<Task> _tasks = [ Task( name: "do something", description: "try to do it fast!!!", ), ];List<Task> _doneTasks = [ Task( name: "task marked as done", description: "something", ),]; 解决方案 So generally speaking, once you want to store anything other than a primitive type ie. String int etc... things get a bit more complex because they have to converted to something that's readable by any storage solution.So despite Tasks being a basic object with a couple strings, SharedPreferences or anything else doesn't know what a Task is or what to do with it.I suggest in general reading about json serialization, as you'll need to know about it either way. This is a good place to start and here is another good article about it.All that being said, it can also be done without json by converting your task to a Map (which is what json serialization does anyway) and storing it to a list of maps. I'll show you an example of doing this manually without json. But again, its in your best interest to buckle down and spend some time learning it.This example will use Get Storage, which is like SharedPreferences but easier because you don't need separate methods for different data types, just read and write.I don't know how you're adding tasks in your app, but this is just a basic example of storing a list of Task objects. Any solution that doesn't involve online storage requires storing locally, and retrieving from storage on app start.So let's say here is your Task object.class Task { final String name; final String description; Task({this.name, this.description});}Put this in your main method before running your appawait GetStorage.init();You'll need to add async to your main, so if you're not familiar with how that works it looks like this.void main() async { await GetStorage.init(); runApp(MyApp());}Normally I would NEVER do all this logic inside a stateful widget, but instead implement a state management solution and do it in a class outside of the UI, but that's a whole different discussion. I also recommend checking out GetX, Riverpod, or Provider reading about them and seeing which one strikes you as the easiest to learn. GetX gets my vote for simplicity and functionality.But since you're just starting out I'll omit that part of it and just put all these functions in the UI page for now.Also instead of only storing when app closes, which can also be done, its easier to just store anytime there is a change to the list.Here's a page with some buttons to add, clear, and print storage so you can see exactly whats in your list after app restart.If you understand whats going on here you should be able to do this in your app, or study up on json and do it that way. Either way, you need to wrap your head around Maps and how local storage works with any of the available solutions.class StorageDemo extends StatefulWidget { @override _StorageDemoState createState() => _StorageDemoState();}class _StorageDemoState extends State<StorageDemo> { List<Task> _tasks = []; final box = GetStorage(); // list of maps gets stored here // separate list for storing maps/ restoreTask function //populates _tasks from this list on initState List storageList = []; void addAndStoreTask(Task task) { _tasks.add(task); final storageMap = {}; // temporary map that gets added to storage final index = _tasks.length; // for unique map keys final nameKey = 'name$index'; final descriptionKey = 'description$index';// adding task properties to temporary map storageMap[nameKey] = task.name; storageMap[descriptionKey] = task.description; storageList.add(storageMap); // adding temp map to storageList box.write('tasks', storageList); // adding list of maps to storage } void restoreTasks() { storageList = box.read('tasks'); // initializing list from storage String nameKey, descriptionKey;// looping through the storage list to parse out Task objects from maps for (int i = 0; i < storageList.length; i++) { final map = storageList[i]; // index for retreival keys accounting for index starting at 0 final index = i + 1; nameKey = 'name$index'; descriptionKey = 'description$index'; // recreating Task objects from storage final task = Task(name: map[nameKey], description: map[descriptionKey]); _tasks.add(task); // adding Tasks back to your normal Task list } }// looping through you list to see whats inside void printTasks() { for (int i = 0; i < _tasks.length; i++) { debugPrint( 'Task ${i + 1} name ${_tasks[i].name} description: ${_tasks[i].description}'); } } void clearTasks() { _tasks.clear(); storageList.clear(); box.erase(); } @override void initState() { super.initState(); restoreTasks(); // restore list from storing in initState } @override Widget build(BuildContext context) { return Scaffold( body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Center( child: Container(), ), TextButton( onPressed: () { final task = Task(description: 'test description', name: 'test name'); addAndStoreTask(task); }, child: Text('Add Task'), ), TextButton( onPressed: () { printTasks(); }, child: Text('Print Storage'), ), TextButton( onPressed: () { clearTasks(); }, child: Text('Clear Tasks'), ), ], ), ); }} 这篇关于Flutter - 每次关闭应用程序时存储对象列表的最佳方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
08-30 05:09