My app gets it data from a REST API.
Depending on the endpoint I get list of complete or partial Account.
When the API responds I call realm.copyToRealmOrUpdate(accounts).
My problem is that if a complete account is already stored in realm and the same partial account but where relation_tx, relation_rx, message_last_rx, message_last_tx are null is in the accounts list, the complete account is overriden completely.
I only want realm to update fields which are not null.
Any suggestions?
Any way I can override the Account.update() method?
#RealmClass
public class Account extends RealmObject {
public String timestamp;
#PrimaryKey
public long id;
public String name;
public String email;
public Relation relation_tx;
public Relation relation_rx;
public Message message_last_rx;
public Message message_last_tx;
}
I think you'll have to manually compare. Don't call realm.copyToRealmOrUpdate(accounts) with the content from the server.
Instead, name your server response serverAccounts. For every account in it: get the account (localAccount) with this id from Realm. If not found (null): add the serverAccount to the DB. If found: update your four fields manually on the localAccount and save the localAccount to the DB.
To optimize the above, you might want to do a single Realm query with a list of ids (from the serverAccounts) and save your changes in one batch to Realm as well.
Related
When using Firebase to store and retrieve objects (POJOs) created by the user (for example: posts or comments), it becomes necessary to pass these objects around the application. But what is the suggested way to keep track of the associated DatabaseReference, location or unique key in the database for this object?
Example scenario
A simple to do list app allows the user to freely add, edit and remove items in their list. So when the user creates an item, something similar to the below would happen:
private Item storeItem(String title) {
String key = mDatabase.child("items").push().getKey(); // Where do we keep this key?
Item item = new Item(title);
mDatabase.child("items").child(key).setValue(item);
return item;
}
Where Item is this Java object:
public class Item {
private String title;
private String description;
public Item() {}
public Item(String title) {
this.title = title;
}
// ...
}
Behind the scenes, this item is added to a RecyclerView, either by inserting the returned Item to the adapter or when a ChildEventListener attached to the "items" reference is fired.
The user then wishes to rename this new item or add text to the description field, so tapping on it in the RecyclerView starts a separate Activity which receives the passed Item and uses getters/setters to make changes.
Now, we'll need to save these changes to the database, which we can do by calling setValue() again, as above. However, we didn't store the key variable from storeItem() so we don't actually know where this item is currently stored in the database.
So, where can we keep track of the created item's key for later use to save changes back to the database?
Possible solutions
There are a number of different paths we could take here, but I'm looking for some guidance on the suggested method, as the Firebase documentation doesn't mention this hurdle. I've outlined some examples that I can think of:
Store the key inside the object. We could add another field to the Item object to store the database key. So within the previous storeItem() method, the key variable is added to the Item constructor and stored in the database as a field.
Create a wrapper object. We could wrap the Item object in a container that has methods such as getItem() and getKey() or getDatabaseReference() and then pass this around the app instead of the Item itself.
Use the DataSnapshot instead. Once the item is created, wait until an attached listener receives it, then use and pass around the retrieved DataSnapshot, which has methods for getKey() and getRef().
Retrieve the object every time it is needed. Instead of passing Item around the app, we could retrieve it from the database every time it is needed, by using the key or DatabaseReference.
Wrapping up
Looking back on this huge question, it seems I might have overcomplicated it a little, but I wanted to be thorough in my explanation. I'm also hoping that it's not purely opinion-based and there currently is some standard way to achieve this.
So I guess my question is: is there a standard method to handle and make changes to Java objects stored in Firebase?
Most developers I see struggling with this end up storing the key inside the Java objects too. To prevent it being duplicated in the JSON, you can annotate it in the Java class:
public class Item {
private String title;
private String description;
#Exclude
public String key;
public Item() {}
public Item(String title) {
this.title = title;
}
// ...
}
See: Is there a way to store Key in class which I cast from Firebase object?
My personal preference in such cases is to keep the DataSnapshot around. The main disadvantage I see in that is that the information on the object-type of the snapshot is spreading out over my code since this exists in multiple places:
snapshot.getValue(Item.class);
I've been lobbying to generify the DataSnapshot class so that it'd become DataSnapshot<Item>, which would solve that problem. I think that is currently being considered in the Firestore SDK for JavaScript/TypeScript.
But lacking such a solution for the Android SDK for the Realtime Database, you're probably better off with the first approach: storing the key inside the Java objects.
I ran across a problem where I am not really sure how to solve it. The project I am working on currently has a model which partly consists of backend stored data and data from the local database.
So what I am trying to Archive is something like that:
Article : [Bunch of Information] & [boolean Subscribed]
The subscribed field is device bound and should not reflect any data on the backend. My question is if it is possible to implement in Room some kind of createIfNotExit() Method that handles the following cases:
Article not present locally: store a copy and set Subscribed to
false
Article present: update all the Information and Keep the
Subscribe-Flag untouched
My idea is to split the model into a separate Subscription-Model holding a reference to the Article. This way I could implement it simply via #Update(OnConfict=Update) etc...
Is there a way to implement a simple #Query method in the DAO that performs what I want?
Sorry if this is a really basic question but I couldn't find any material about best practices handling this case.
Thank you in advance!
For example, your entity is:
#Entity(tableName = "articles")
public final class Article {
#PrimaryKey
public long serverId;
public String title;
public String url;
public boolean isSubscribed;
}
You may write this method in DAO:
#Query("INSERT OR REPLACE INTO articles (serverId, title, url, isSubscribed) VALUES (:id, :title, :url,
COALESCE((SELECT isSubscribed FROM articles WHERE id = :id), 0));")
void insertOrUpdateArticle(long id, String title, String url);
Another option - write this logic in your repository and use two simple operations: select and update
I'm using Firebase as my database for my Android project. In this project, I have users with minimal data associated with them.
users{
1234-567-897:{
Display:"Name",
Email:"foo#bar.ca"
},
...
I made this structure with a basic object User with two local string variables.
My issue is that I now need to add a schedule to each user, which consists of a list of Events, each event with it's own information(Start time, End time, etc.)
I understand that my structure would probably look something like this:
users{
1234-567-897:{
Display:"Name",
Email:"foo#bar.ca",
Schedule:{
event1:{
name:"Meeting",
startTime:1,
endTime:2
},
event2:{...}
},
Sschedule2:{...}
},
But I have no idea how to go about creating this type of structure with Firebase. I was initially going to use an ArrayList to hold the objects of Schedules and Events but after reading the Firebase documentation, it looks like they don't support ArrayList storing. An alternative to this that I was considering was to create a separate table of schedules and reference them with uids.
Appreciate any advise regarding creating this structure, thanks!
These seem to be the minimal classes needed for your data:
public class Event {
public String name;
public Long startTime;
public Long endTime;
}
public class User {
public String Display;
public String Email;
public Map<String, Event> Schedule;
}
The Schedule is a map, where the keys are event1 and event2.
I didn't add Schedule2 because its type is unspecified.
I am making an android app. I have a User class which has many getters and setters.
I have many activities in my app and by just creating a single object of User class I want to access that object from many activities.
How can I do that?
Thank you for the answer. But the scenario is like this. I have a database and in there is a table user which contains all the information about the user registration like name,age, password, emailID, last logged in etc. Each of these fields are there in the user class. Now my first activity is for accepting the terms and conditions page. If the user accepts it then I want to update that particular column in the database table. Then in next activity user registration will happen. Then I need to store that data in the database table. So in the same row all that data has to be inserted in the database. How will this be done
Try using singleton:
class User {
private static User sInstance;
private User() {
}
public static User getInstance() {
if(sInstance == null) {
sInstance = new User();
}
return sInstance;
}
// ... other methods
}
In activities:
User.getInstance().doSomething();
More here: https://stackoverflow.com/a/16518088/1979756
UPDATE:
If you are using db, look at SQLiteOpenHelper. Extend it and manage all data there. Also, you can use some libs to manage your db data: ormLite, greenDAO, realm, etc. You can find a lot of info about them on SO.
To serve a backend for an Android App i am using Google App Engine together with Objectify (4.0.3b).
On the backend I have a simple User Entity, which has a list of Users (friends) as relationship.
#Entity
public class User {
#Id
private String email;
#Load
private List<Ref<User>> friends = new ArrayList<Ref<User>>();
private User() {
}
public List<User> getFriends() {
ArrayList<User> friendList = new ArrayList<User>();
for (Ref<User> ref : this.friends) {
friendList.add(ref.get());
}
return friendList;
}
public void setFriends(List<User> friends) {
List<Ref<User>> refs = new ArrayList<Ref<User>>();
for (User user : friends) {
refs.add(Ref.create(user));
}
this.friends = refs;
}
}
Now when I have following Users stored in the Database for instance : user1 and user2:
user1 has user2 in his friend list and vice versa
When trying to fetch a User object (that has the above cycle reference) from my Endpoint, the Android client throws the following exception:
com.google.appengine.repackaged.org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: java.util.ArrayList[0]...
In this post Infinite Recursion with Jackson JSON and Hibernate JPA issue they recommend to use #JsonIgnore on the field or the getter/setter method.
But on the client side i need to access the friends list by these getter/setter methods (from the generated client library object), so this doesn't help me.
Another tip is to use #JsonManagedReference and #JsonBackReference, which in my case can't be applied since ManagedReference and BackReference would pointto the same friends field.
What I think could solve my Problem is the #JsonIdentityInfo Annotation which is available since Jackson 2.0.
My problem now is that I don't know how I can use this Annotation with Google App Engine.
GAE uses jackson-core-asl-1.9.11, which unfortunately does not have the #JsonIdentityInfo, as it obviously is depending on a version below 2.0.
Does anybody know, how I can use the latest Jackson Version (2.4) in Google App Engine to use the #JsonIdentityInfo feature?
Or is there a better approach for my problem?
The best approach would be to define a DTO class to use as a return parameter for your endpoint and use that to flatten the JSON response (meaning not sending the infinite loop of friend's friends).