'Flutter Hive save custom object with list of custom objects gone after restarting app

I am using the Hive- Package in my project to store some data locally. That has been working fine so far, but now I am facing an issue:

I have a Custom-Class which also has a field with another Custom-Class:

part 'hive_vitals_interface.g.dart';

@HiveType(typeId: 1)
class HiveVitals extends HiveObject {
  @HiveField(0)
  String? id;
  @HiveField(1)
  DateTime? date;
  @HiveField(2)
  List<HiveDiscomfort> otherDiscomfort;
  @HiveField(3)
  List<HiveDiscomfort> mentalDiscomfort;

  HiveVitals({
    this.id,
    this.date,
    this.otherDiscomfort = const [],
    this.mentalDiscomfort = const [],
  });
}

And my HiveDiscomforts-Class:

part 'hive_discomfort_interface.g.dart';

@HiveType(typeId: 2)
class HiveDiscomfort extends HiveObject {
  @HiveField(0)
  String? title;
  @HiveField(1)
  int? intensity;

  HiveDiscomfort({
    this.title,
    this.intensity,
  });
}

I am trying to save HiveVitals like this:

  static Future<void> addVitals(HiveVitals hiveVitals) async {
    final vitalsBox = getVitalsBox();

    await vitalsBox.put(hiveVitals.date!.toIso8601String(), hiveVitals);

  }

And retrieve it like this:

  static List<HiveVitals> getVitals() {
    Box<HiveVitals> box = getVitalsBox();
    List<HiveVitals> hiveVitals = box.values.toList();
    return hiveVitals;
  }

Problem:

I don't get any errors. In fact when saving my object and checking it in the debugger, everything is saved correctly. However when restarting the app, my List<HiveDiscomfort> fields are always empty again! But the rest of the HiveVitals-Fields are still saved correctly!?

What am I missing here? I don't get it... Any help is appreciated! Let me know if you need anything else!

Also opened an issue on Github.



Solution 1:[1]

I use this method and it works for me as List doesn't require registering an adapter:

await Hive.openBox<List>(bookmarks);

Add data like this:

boxValue.put(index, [
                    question.title,
                    question.options,
               ],
);

And you can access the data via ValueListenableBuilder.

Solution 2:[2]

If you're saying data is being saved and everything worked fine till you didn't restart the app. So the problem may be : After restarting your app, you had may put a function that cleared all the data saved in Hive as soon as app starts. Check this one.If like this will there then remove that line or function that clear all the data from hive DB.

Solution 3:[3]

Updated answer:

My previous solution got me thinking and I think I know why nested lists are not persisted. It seems like hive is not checking for list equality and therefore never persist the changes, but uses the object as it is currently in memory. So, that is why as long as the application runs the object is correctly in memory, but when the app is closed hive does not persist the data as it thinks that the data (here the lists) never changed, even though they changed (this is my guess now without looking further into the code of the hive package).

So that means the solution would be to check for equality of the lists in the equals method. For this example it would be:

@override
bool operator ==(Object other) =>
    identical(this, other) ||
    other is HiveVitals &&
        runtimeType == other.runtimeType &&
        id == other.id &&
        date == other.date &&
        listEquals(otherDiscomfort, other.otherDiscomfort) &&
        listEquals(mentalDiscomfort, other.mentalDiscomfort);

For me this solution works.

Old answer:

I had the same issue...

I try to explain my solution based on this example. Given an object HiveVitals hiveVitals = HiveVitals(), whenever I tried to add something to the nested list of my custom object like hiveVitals.otherDiscomfort.add(), it was saved but not persisted (it was gone whenever I restarted the app). What I did was the following when I wanted to add something to the nested list:

List<HiveDiscomfort> tempList = [...hiveVitals.otherDiscomfort];
tempList.add(newData);
hiveVitals.otherDiscomfort = tempList;

That worked for me, now my data is persisted.

Solution 4:[4]

I think this is a problem with the package because I have the same issue that everything works okay but with restarting the app the data disappears. So I asked the question at hive flutter github and no answers yet. So I ask u to open an issue at hive flutter github to let them know that this is a real problem we face it.

Solution 5:[5]

Here are a couple of hints about the issue which may be why the data is lost:

  • Hive FAQ: What happens if my app is killed? The worst thing that can happen is that you lose the last entry if it isn't written completely yet. Hive has built-in integrity checking and crash recovery and takes care of everything.
  • Limitations: Keys have to be 32 bit unsigned integers or ASCII Strings with a max length of 255 chars. The supported integer values include all integers between -2^53 and 2^53, and some integers with larger magnitude Objects are not allowed to contain cycles. Hive will not detect them and storing will result in an infinite loop. Only one process can access a box at any time. Bad things happen otherwise. Boxes are stored as files in the user's app-directory. Common illegal characters/symbols such as /%& should therefore be avoided.

The most likely cause though may be related to improper implementation of the Hive Relationships behavior. Are you using HiveLists? If not look into this more closely. Secondly, you may just be trying to save too much when the app is killed. Try changing the save operation before the app is killed to verify proper behavior.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 tdy
Solution 2 Lakshydeep Vikram Sah
Solution 3
Solution 4 Mohammad Sami
Solution 5 Tommie C.