Flutter - how to store lists of Strings: (GetStorage or Shared Preferences). using android

3,088

Sounds like your code is based on my answer to your original question about this.

If that's the case, then the key tasks is the key to the entire list of maps, not a single map or Task. So it's behaving as expected when it wipes all of your tasks.

In order to persist any changes, you'd have to remove that particular map (Task) from storageList then overwrite the box again with box.write('tasks', storageList); It will save over the same list of maps and persist any deletions you made.

If you share your code where you're trying to delete the task and whats going on around it I can give you a more specific example.

EDIT: Answering question in comments.

If you wanted to go the UniqueKey route you wouldn't need the index at all. You could do something like this.

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

When you add a new Task it would look like this.

final task = Task(
    description: 'test description',
    name: 'test name',
    key: UniqueKey().toString());

Then you could use a Map of maps instead of a list of maps and use the key for both.

  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
  }

Then your restore function would look like this:

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

Then when you go to delete, you iterate through the list and find the matching key.

Share:
3,088
Louis
Author by

Louis

Updated on December 28, 2022

Comments

  • Louis
    Louis over 1 year

    So, I have come across a solution for this problem using Get_storage thanks to a couple of great explanations about the topic. I managed to work with getx and the Provider package to save data when adding new stuff and reading it when starting the application (thats the behavior i'm going for here). Said that, i'm having a hard time trying to remove data from memory.

    Context
    The project is a to-do list app, the front end is working perfectly, but when it comes to storage it gets more complicated. The thing is that i'm very new to flutter and mobile development, i recieved some help but this kind of stuff is still foggy in my brain, i could not remove data using the same logic. When i called box.Remove('key') like the docs say, my ENTIRE list got removed. I don't have a single clue why that happaned.

    And so i wonder if i could understand it more by reading through some more explanations, i know Shared Preferences is a great deal do work with this kind of situation, but i would also be confortable with a solution using get_storage since i'm more familiar with it.

    the code:\

    I'm calling these lists inside a listView on a different file with the help of Provider - -

    List<Task> _tasks = [
    Task(
      name: "Title",
      description: "Description",
    ),
    

    ];

    Adding tasks to my ListView - -

    void add(String newTitle, newDesc) {
        final task = Task(name: newTitle, description: newDesc);
        _tasks.add(task);
    
        notifyListeners();
      }
    

    Here is the removal of a task from the ListView - -

    void removeTasks(Task task) {
    _tasks.remove(task);
    
    notifyListeners();
    

    }

    I tried to implement a logic to write and read data, it worked. But i also tried to use this removeTasks method to remove from storage as well by calling box.Remove('tasks'); ('tasks' was the key passed to the writing and reading methods). It removed everything from memory since my listview got empty.

    Since i'm not that experienced, i went through the documentation and could understand some of the SharedPreferences Explanation (same with got_storage) but i'm having a hard time when trying to apply it to my code.

    I would appreciate any help using get_storage OR shared preferences to this problem.

    Where i'm calling the deletion:

    // 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);
                    }
                  },
                 
                );
              },
            );
          },
        );
      }
    }
    

    So i spent some time translating the code, but i think that it does not match any of flutter's good practices principles.

    I also tried calling storageList.remove(task); and then rewriting it with the box.write('tasks', storageList); but nothing was removed from the memory (maybe because i didn't loop through the whole storageLists searching for the right index i guess)

  • Louis
    Louis about 3 years
    I think I understand what u explained, I managed to remove the tasks by applying what you said, my hardest difficulty here I think is related to work with the indexes on the logic u presented, because when I remove elements from the storageList, the remaining tasks indexes does not decrement, differently from the, _tasks list, that decrement the indexes when something is removed, and so when I try to read the tasks through that loop you showed on the other post they cannot read the nameKeys and return null for every task after the one removed.
  • Loren.A
    Loren.A about 3 years
    Yeah that solution was just something to get you started in the world of persistence, it was never an end all be all for your app. The issues you're facing with index makes sense. When I get some more time I can have a look at your code but in the mean time, you've already sussed out the problem. Now you can perhaps find a way around the index issue or come up with a better solution all together to maintain a unique key for each task.
  • Louis
    Louis about 3 years
    thank you very much Loren, i thought about a logic to deal with the indexes. You helped me a lot and i will certainly make a cleaner way through persistance thanks to you! :D
  • Loren.A
    Loren.A about 3 years
    No problem. Maybe check out Unique Keys, you can make them a part of your Task objects then when you delete something can loop through the list and find the matching key, and it will only remove that. Convert them to string and they can also be the key to map storage as well. One of many possible solutions. api.flutter.dev/flutter/widgets/UniqueKey-class.html
  • Louis
    Louis about 3 years
    if i wanted to convert them to strings, then i should do the same you did before right ? by passing it to a map, then passing the map to a storageList. Maybe in this case the thing would be to create a key attribute inside Task(name, description, key) and passing this attribute within the addTasks() as something like.... final keyKey = 'key$index"; idk, i have to think about how i'd implement that to compare this key to the _tasks index when Reading the file.
  • Loren.A
    Loren.A about 3 years
    Sorry I spaced on responding to this, you have the right idea but you wouldn't need the index at all if you use UniqueKey. As the index was just a quick hack to generate a unique map key in my previous example. See updated answer.