Flutter - 如何存储字符串列表:(GetStorage 或 Shared Preferences)。使用安卓
Posted
技术标签:
【中文标题】Flutter - 如何存储字符串列表:(GetStorage 或 Shared Preferences)。使用安卓【英文标题】:Flutter - how to store lists of Strings: (GetStorage or Shared Preferences). using android 【发布时间】:2021-06-28 00:30:45 【问题描述】:因此,由于对该主题的一些很好的解释,我已经使用 Get_storage 找到了解决此问题的方法。我设法使用 getx 和 Provider 包在添加新内容时保存数据并在启动应用程序时读取它(这就是我在这里要采取的行为)。也就是说,我很难从内存中删除数据。
上下文 该项目是一个待办事项列表应用程序,前端运行良好,但在存储方面变得更加复杂。问题是我对颤振和移动开发非常陌生,我得到了一些帮助,但这种东西在我的脑海中仍然模糊不清,我无法使用相同的逻辑删除数据。当我像文档所说的那样调用 box.Remove('key') 时,我的整个列表都被删除了。我不知道为什么会这样。
所以我想知道我是否可以通过阅读更多解释来更多地理解它,我知道共享首选项在这种情况下非常有用,但我也会对使用 get_storage 的解决方案感到满意,因为我'我比较熟悉。
代码:\
我在 Provider 的帮助下在不同文件的 listView 中调用这些列表 - -
List<Task> _tasks = [
Task(
name: "Title",
description: "Description",
),
];
将任务添加到我的 ListView - -
void add(String newTitle, newDesc)
final task = Task(name: newTitle, description: newDesc);
_tasks.add(task);
notifyListeners();
这里是从 ListView 中移除一个任务 - -
void removeTasks(Task task)
_tasks.remove(task);
notifyListeners();
我尝试实现一个逻辑来写入和读取数据,它奏效了。但我也尝试通过调用 box.Remove('tasks'); 来使用这个 removeTasks 方法从存储中删除。 ('tasks' 是传递给写入和读取方法的键)。自从我的列表视图变空后,它从内存中删除了所有内容。
由于我没有那么有经验,我浏览了文档并且可以理解一些 SharedPreferences 解释(与 got_storage 相同),但我在尝试将其应用于我的代码时遇到了困难。
如果使用 get_storage 或共享偏好来解决此问题,我将不胜感激任何帮助。
我在哪里调用删除:
// bool variables that control the state of the screen
// since i can change it to show done tasks or on goind tasks
// dont mind that, i think its irrelevant to the problem.
//
bool isActiveDoing = true;
bool isActiveDone = false;
List finalArray = []; //it will store the tasks
class TaskList extends StatefulWidget
@override
_TaskListState createState() => _TaskListState();
class _TaskListState extends State<TaskList>
@override
Widget build(BuildContext context)
//dont mind the if else as well, its not part of the problem
//just using it to handle the state of the screen
if (isActiveDoing)
finalArray = Provider.of<TasksFunctions>(context).tasks;
//TasksFunctions is a class with methods on regards to the storage
//it contains add tasks, remove, etc... i'm using provider to
//link those to the screens with the notifyListeners
if (isActiveDone)
finalArray = Provider.of<TasksFunctions>(context).doneTasks;
//now here is where i call the class tha has the deletion method
return Consumer<TasksFunctions>(
builder: (context, tasksFunctions, child)
return ListView.builder(
//list view tha has all the tasks
itemCount: finalArray.length,
itemBuilder: (context, index)
final task = finalArray[index];
//using the slidableWidget to wrap the deletion method
return SlidableWidget(
onDismissed: (action)
if (isActiveDoing)
Provider.of<TasksFunctions>(context, listen: false)
.removeTask(task);
//so here is where i'm deleting those tasks, calling that method
//listed up on this post
if (isActiveDone
Provider.of<TasksFunctions>(context, listen: false)
.removeDone(task);
,
);
,
);
,
);
所以我花了一些时间翻译代码,但我认为它不符合 Flutter 的任何良好实践原则。
我也试过调用 storageList.remove(task);然后用 box.write('tasks', storageList); 重写它但没有从内存中删除任何内容(可能是因为我没有遍历整个 storageLists 来搜索我猜的正确索引)
【问题讨论】:
【参考方案1】:听起来您的代码是基于my answer to your original question about this。
如果是这样,那么键 tasks
是整个映射列表的键,而不是单个映射或 Task
。因此,当它擦除您的所有任务时,它的行为符合预期。
为了保留任何更改,您必须从 storageList
中删除该特定地图(任务),然后用 box.write('tasks', storageList);
再次覆盖该框,它将保存相同的地图列表并保留您所做的任何删除.
如果您在尝试删除任务的地方分享您的代码以及周围发生的事情,我可以给您一个更具体的示例。
编辑:在 cmets 中回答问题。
如果您想走UniqueKey
路线,则根本不需要索引。你可以这样做。
class Task
final String name;
final String description;
final String key; // not an actual Key but will take the String value of a UniqueKey
Task(this.key, this.name, this.description);
当您添加一个新的Task
时,它会如下所示。
final task = Task(
description: 'test description',
name: 'test name',
key: UniqueKey().toString());
然后您可以使用地图的Map
而不是地图列表,并为两者使用密钥。
Map storageList = ;
void addAndStoreTask(Task task)
_tasks.add(task);
final Map storageMap = ; // temporary map that gets added to storage
storageMap['name'] = task.name;
storageMap['description'] = task.description;
storageMap['key'] = task.key;
storageList[task.key] = storageMap; // adding temp map to storageList
box.write('tasks', storageList); // adding map of maps to storage
那么你的恢复函数应该是这样的:
void restoreTasks()
storageList = box.read('tasks'); // initializing list from storage
storageList.forEach((key, value) // value here is each individual map that was stored
final task =
Task(name: value['name'], description: value['description'], key: key);
_tasks.add(task);
);
然后当你去删除时,你遍历列表并找到匹配的键。
【讨论】:
我想我明白你的解释,我设法通过应用你所说的来删除任务,我认为我在这里最难的困难与使用你提出的逻辑上的索引有关,因为当我从 storageList 中删除元素,剩余的任务索引不会减少,与 _tasks 列表不同,当删除某些内容时会减少索引,因此当我尝试通过您在另一篇文章中显示的循环读取任务时,他们不能读取 nameKeys 并为删除后的每个任务返回 null。 是的,该解决方案只是让您在持久性世界中开始的东西,它绝不是您的应用程序的全部。您面临的索引问题是有道理的。当我有更多时间时,我可以查看您的代码,但与此同时,您已经解决了问题。现在,您也许可以找到解决索引问题的方法,或者一起提出更好的解决方案来为每个任务维护一个唯一的键。 非常感谢 Loren,我想到了处理索引的逻辑。你帮了我很多,多亏了你,我一定会通过坚持不懈地走一条更清洁的路! :D 没问题。也许看看Unique Keys
,你可以让它们成为你Task
对象的一部分,然后当你删除某些东西时,可以循环遍历列表并找到匹配的键,它只会删除它。将它们转换为字符串,它们也可以成为映射存储的关键。许多可能的解决方案之一。 api.flutter.dev/flutter/widgets/UniqueKey-class.html
如果我想将它们转换为字符串,那么我应该和你之前做的一样吗?通过将其传递给地图,然后将地图传递给 storageList。也许在这种情况下,事情将是在 Task(name, description, key) 中创建一个 key 属性,并在 addTasks() 中传递这个属性,就像.... final keyKey = 'key$index"; idk, i必须考虑如何在读取文件时将此键与 _tasks 索引进行比较。以上是关于Flutter - 如何存储字符串列表:(GetStorage 或 Shared Preferences)。使用安卓的主要内容,如果未能解决你的问题,请参考以下文章
Flutter - 如何在 GetStorage 中存储列表?