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

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.

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.

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.

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.

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.

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.

Related

How to make "compute()" function insert data to sqlite while in isolated process?

I'm working on flutter app that uses php apis for server and sqlite for local data.
The problem is with "compute()".
Here is the explanation :
I have three functions that receives data from api on the server, then add the data to my local database (sqlite) table.
First function to get data from server.
Future<List<Map<String, dynamic>>> getServerData(int vers)async {
//my code
}
Second function to insert data into local database:
Future<int> addNewData(List<Map<String, dynamic>>)async {
//my code
}
Third function to call the first and second function:
Future<bool> checkServerData(int vers)async {
List<Map<String, dynamic>> sdt= await getServerData(vers);
int res=await addNewData(sdt);
if(res>0) return true;
else return false;
}
I want to call the third function in a compute function:
compute(checkServerData, 2);
When did that I found this error:
null check operator used on null value.
Note*:
If I used it without calling local database it works good.
The error appears if I called the database to insert data into.
When I searched about this issue I found that it's not allowed to access any resources which generated in one thread from another thread. But I didn't understand exactly how to resolve it or how to use another way that do the same idea.
After searching about the issue specified, I found those workaround solutions:
1: if the process is very important to work in background, you can use the Isolate package classes and functions which allow all isolated processes or contexts to share data between them as messages sending and receiving. But it's something complex for beginners in flutter and dart to understand these things, except those who know about threading in another environments.
To now more about that I will list here some links:
Those for flutter and pub documentation:
https://api.flutter.dev/flutter/dart-isolate/dart-isolate-library.html
https://api.flutter.dev/flutter/dart-isolate/Isolate-class.html
https://pub.dev/packages/flutter_isolate
This is an example in medium.com website:
https://medium.com/flutter-community/thread-and-isolate-with-flutter-30b9631137f3
2: the second solution if the process isn't important to work on background:
using the traditional approaches such as Future.builder or async/await.
You can know more about them here:
https://www.woolha.com/tutorials/flutter-using-futurebuilder-widget-examples
https://dart.dev/codelabs/async-await
and you can review this question and answers in When should I use a FutureBuilder?

All string data appears as "Instance of" when i print

recently i made a couple of form pages( text input,radio button, that kind of stuff), and they used to work pretty well. I came back to them after working in another part of the app, and realize that it doesn't work anymore.
I checked a couple of things and realized that all text input data comes as "Instance of thing". So when i send the data to the backend and check it, it appears as null. As far as i know this means that the string data the user input is not being saved as a string inside my variables, but as instances and that's why it doesn't work.
Any ideas as to why this happened? As far as i remember i didn't change anything in these pages.
I'm using provider to maintain the data locally.
If snippets of code are needed please ask.
Most probably if you are getting "Instance of thing" & also null, then you need to await on your data.
class YourClass {
int yourVariable = 0;
String anotherVariable = "string";
#override
String toString() {
return "YourVariable : $yourVariable , AnotherVariable : $anotherVariable";
}
}
You have to override the toString() method and return your objects like above and call toString() method when you print the object

How to cache a value returned by a Future?

For my Flutter app I'm trying to access a List of Notebooks, this list is parsed from a file by the Api. I would like to avoid reading/parsing the file every time I call my notebooks getter, hence I would like something like this:
if the file had already been parsed once, return the previously parsed List<Note> ;
else, read and parse the file, save the List<Note> and returns it.
I imagine something like this :
List<Notebook> get notebooks {
if (_notebooks != null) {
return _notebooks;
} else {
return await _api.getNotebooks();
}
}
This code is not correct because I would need to mark the getter async and return a Future, which I don't want to. Do you know any solution for this problem, like caching values ? I also want to avoid initializing this list in my app startup and only parse once the first time the value is needed.
you can create a singleton and you can store the data inside a property once you read it, from next time onwards you can use the same from the property.
You can refer this question to create a singleton
How do you build a Singleton in Dart?

How to properly add user data using Bloc && How to properly use Google Places API

I'm having difficulties in two areas:
1) When a user successfully logs into their account using phone auth in Firestore, I take them to an "Edit profile" page so they can add their profile information. I get an error saying that I can't add data to a null user class or add data to a class within a class.
I currently have my user class setup something like the following:
class User {
String points;
Name name;
User({this.points, this.name});
}
class Name {
String firstName;
String lastName;
Name({this.firstName, this.lastName})
}
As you can see, I have a class within a class and when I try to add a value, it says I can't. I've tried doing it like
_bloc.user.name.firstName = value
And I've tried like
Name newName = Name();
newName.first = value.
The second one seems to work but it doesn't seem right. I'm hoping you could help me understand how to properly approach adding data for new users when I have a class within a class.
The second issue is understanding how to properly use the Places API. I'm currently learning from the below repo, but it's outdated and there's a couple lines I can't seem to figure out how to change. I also can't seem to find an updated tutorial since the October app crashing update.
https://github.com/alfianlosari/flutter_placez
Thanks in advance for your help!

What are the options for REST frameworks in D? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 3 years ago.
Improve this question
I would like to use d to create a RESTful web application.
What are the most actively maintained and contributed projects that are worth considering? A short comparison of these web frameworks with pluses and minuses will be nice.
My search lead me to only one project, which seems like an excellent framework:
vibe.d
Are there other projects which are minimal in nature like sinatra?
I've heard good things about vibe.d http://vibed.org/
Though, I've never personally used it because I wrote my own libraries well before vibe came out.
https://github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff
vibe is better documented, so you might be better off going there, but here's how my libraries work:
cgi.d is the base web interface (use -version=embedded_httpd when compiling to use its own web server instead of CGI if you want), and I offer some RESTy stuff in a separate file called web.d. It depends on cgi.d, dom.d, characterencodings.d, and sha.d. You might also want database.d and mysql.d for connecting to a mysql database.
The way web.d works is you just write functions and it automatically maps them to url and formats data.
http://arsdnet.net/cgi-bin/apidemo/add-some-numbers
The source code to that portion is:
import arsd.web;
class MySite : ApiProvider {
export int addSomeNumbers(int a, int b) { return a+b; }
}
mixin FancyMain!MySite;
web.d automatically generates the form you see there, parses the url into the types given, and formats the return value into either html, json, or sometimes other things (for example, objects can be made into tables).
There is also an envelopeFormat url param that can wrap it in more json, best for machine consumption:
http://arsdnet.net/cgi-bin/apidemo/add-some-numbers?a=1&b=2&format=json&envelopeFormat=json
web.d.php in my github shows one way you can consume it, and web.d itself automatically generates javascript functions to call from the client:
MySite.addSomeNumbers(10, 20).get(function(answer) { alert("Server replied: " + answer); });
answer would be of the type returned by the D function.
If you don't want/need the automatic function wrapping, cgi.d alone gives access to the basic info and writing functions:
void requestHandler(Cgi cgi) {
// there's cgi.get["name"], cgi.post["name"], or cgi.request("name"), kinda like php
cgi.write("hello ", cgi.request("name"));
}
mixin GenericMain!requestHandler;
But yeah, most the documentation that exists for my library is just me talking about it on forums... I think once you've done one function it isn't hard to figure out, but I'm biased!
edit: copy/paste from my comment below since it is pretty relevant to really getting RESTy:
I actually did play with the idea of having urls map to objects and the verbs go through: web.d also includes an ApiObject class which goes: /obj/name -> new Obj("name"); and then calls the appropriate methods on it. So GET /obj/name calls (new Obj("name")).GET();, same for POST, PUT, etc. Then /obj/name/foo calls (new Obj("name").foo(); with the same rules as I described for functions above.
But I don't use it as much as the plain functions for one because it is still somewhat buggy.... and it is still somewhat buggy because I don't use it enough to sit down and fit it all! lol
You use it by writing an ApiObject class and then aliasing it into the ApiProvider:
import arsd.web;
class MySite : ApiProvider {
export int addSomeNumbers(int a, int b) { return a+b; }
alias MyObject obj; // new, brings in MyObject as /obj/xxx/
}
And, of course, define the object:
class MyObject : ApiObject {
CoolApi parent;
string identifier;
this(CoolApi parent, string identifier) {
this.parent = parent;
this.identifier = identifier;
/* you might also want to load any existing object from a database or something here, using the identifier string, and initialize other members */
// for now to show the example, we'll just initialize data with dummy info
data.id = 8;
data.name = "MyObject/" ~ identifier;
}
/* define some members as a child struct so we can return them later */
struct Data {
int id;
string name;
Element makeHtmlElement() {
// for automatic formatting as html
auto div = Element.make("div");
import std.conv;
div.addChild("span", to!string(id)).addClass("id");
div.appendText(" ");
div.addChild("span", name).addClass("name");
return div;
}
}
Data data;
export Data GET() {
return data;
}
export Data POST(string name) {
parent.ensureGoodPost(); // CSRF token check
data.name = name;
// normally, you'd commit the changes to the database and redirect back to GET or something like that, but since we don't have a db we'll just return the modified object
return data;
}
// property accessors for the data, if you want
export int id() {
return data.id;
}
}
mixin FancyMain!MySite;
Then you can access it:
http://arsdnet.net/cgi-bin/apidemo2/obj/cool/
BTW the trailing slash is mandatory: this is one of the outstanding bugs I haven't gotten around to fixing yet. (The trailing slash code is more complicated than it should be, making this harder to fix that it might look.)
Anyway, you can see the object rendered itself as html via makeHtmlElement. This is a good time to showcase other formats:
http://arsdnet.net/cgi-bin/apidemo2/obj/cool/?format=table
table, also try csv, and of course, json
http://arsdnet.net/cgi-bin/apidemo2/obj/cool/?format=json
or for machine consumption:
http://arsdnet.net/cgi-bin/apidemo2/obj/cool/?format=json&envelopeFormat=json
and the property is available too:
http://arsdnet.net/cgi-bin/apidemo2/obj/cool/id
Another major outstanding bug is that the automatically generated Javascript functions can't access child objects at all. They only work on functions on the top level ApiProvider. Another bug that is harder to fix than it might seem, and I'm not particularly driven to do so because the top-level functions can do it all anyway. Of course, you could make the URLs yourself on the xmlhttprequest and access it that way.
Let's also demo POST by slapping together a quick form:
http://arsdnet.net/cgi-bin/apidemo2/poster
you can submit something and see the POST handler indeed reset the name. (BTW note the action has that trailing slash: without it, it silently redirects you! I really should fix that.)
Anyway, bugs notwithstanding, the core of it works and might be the closest thing to full blown REST D has right now.
At the moment of writing this text there is no framework for building true RESTful web services that I know of. However, you should be able to easily build one on top of vibe.d or Adam's web modules that he already mentioned above.
You can take a look at what I'm building. Still extremely alpha, but I'm attempting to build a Rails-like framework in D: http://jaredonline.github.io/action-pack/
I know this is a really late answer, but I figured someone might come by this one day, since it has been so long and a lot of changes has happened within the D community, especially towards web development.
With Diamond you can write RESTful web applications without hacking something together, since it supports it within the framework.
http://diamondmvc.org/docs/backend/#rest
You can try Hunt Framework.
routes setting
GET /user/{id} user.detail
app/UserController.d souce code:
module app.controller.UserController;
import hunt.framework;
class User
{
int id;
string name;
}
class UserController : Controller
{
mixin MakeController;
#Action
JsonResponse detail(int id)
{
auto user = new User;
user.id = id;
user.name = "test";
return new JsonResponse(user);
}
}
Request http://localhost:8080/user/123
{
"id": 123,
"name": "test"
}