Flutter-每次关闭应用程序时存储对象列表的最佳方法? [英] Flutter - Best way to store a List of Objects everytime i close the application?

查看:51
本文介绍了Flutter-每次关闭应用程序时存储对象列表的最佳方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

情况:
因此,我对Flutter和移动开发非常陌生,因此我对Dart不太了解.而且我从有类似问题的人那里读了一些解决方案,但没有设法将这些解决方案用于我自己的事情.

The situation:
So, i'm very new to Flutter and mobile development, thus i dont know much about Dart; And i've read some solutions from people with similar problems but didnt manage to work these solutions to my own thing.

问题:
我有一个具有2个对象列表的待办事项应用程序,我想在用户重新打开该应用程序时存储这些列表.

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 im storming thorwards this problem due to the lack of experience... And so i decided to come asking for some light.

我尝试过的事情:
我遇到过针对此问题的不同解决方案,对于这种情况,它们似乎都太复杂了(与将列表保存到存档中时的习惯相比),包括:将列表编码为地图并转换为使用SharedPreferences之前,使用SQlite数据库之前的字符串(我遇到的每个教程都让我觉得我会用战车杀死一只蚂蚁,对火力堡也是如此).

What i've tried:
I have come across differente solutions for this problem and all of them seemed waaaaay 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).

问题的结构:
ToDo屏幕上有一个ListView.builder调用2个数组:正在进行的任务和已完成的任务,每当用户进行更改时,我都希望将其写入手机.IDK,如果我只能通过调用某些package方法来尝试从类所属的类中保存这些数组,或者如果可能的话,我应该尝试存储整个应用程序.

Structure of the problem:
ToDo screen with a ListView.builder calling 2 arrays: ongoing tasks and done tasks each of wich 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 wich they belong by calling some packages methods, or if i should try to store the entire application if such thing is possible.

结论:
有没有一种简单的方法可以解决此问题,或者我应该为此使用诸如firebase之类的强大功能?即使我不习惯使用Firestore,所以我还是不知道如何应用此类工具来保存数据.

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.

列表的结构方式:

List<Task> _tasks = [
    Task(
      name: "do something",
      description: "try to do it fast!!!",
    ),
  ];

List<Task> _doneTasks = [
 Task(
      name: "task marked as done",
      description: "something",
    ),
];

推荐答案

通常来说,一旦您要存储除原始类型即以外的任何内容,就可以了. String int 等...事情变得更加复杂,因为它们必须转换为任何存储解决方案都可以读取的内容.

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.

因此,尽管 Tasks 是带有几个字符串的基本对象,但SharedPreferences或其他任何内容都不知道 Task 是什么或如何处理.

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.

我建议一般阅读有关json序列化的内容,因为您将需要以任何一种方式来了解它.这是一个很好的起点

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.

话虽如此,通过将您的任务转换为 Map (无论如何,这是json序列化的工作)并将其存储到地图列表中,也可以在没有json的情况下完成.我将向您展示一个在没有json的情况下手动执行此操作的示例.但同样,为了您的最大利益,请妥协并花一些时间来学习它.

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.

此示例将使用获取存储空间,它与SharedPreferences类似,但更容易,因为您不需要用于不同数据类型的单独方法,只需 read write .

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.

我不知道您如何在应用程序中添加任务,但这只是存储 Task 对象列表的一个基本示例.任何不涉及在线存储的解决方案都需要在本地存储,并在应用启动时从存储中检索.

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.

所以我们说这是您的 Task 对象.

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 app

await GetStorage.init();

您需要在主机中添加 async ,因此,如果您不熟悉其工作原理,则如下所示.

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

通常,我永远不会在有状态的小部件内执行所有这些逻辑,而是实现状态管理解决方案并在UI之外的类中进行操作,但这是一个完全不同的讨论.我还建议您查阅GetX,Riverpod或Provider上的有关它们的文章,并了解最容易学习的是哪一个.GetX赢得了我对简单性和功能性的投票.

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.

但是,由于您才刚刚开始,因此我将忽略其中的一部分,而现在将所有这些功能都放在UI页面中.

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.

如果您了解此处发生的情况,则应该可以在您的应用中执行此操作,或者研究json并以此方式进行操作.无论哪种方式,您都需要围绕 Maps 以及本地存储如何与任何可用的解决方案结合使用.

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-每次关闭应用程序时存储对象列表的最佳方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆