realm with parceler to pass data across activities and services - android

I am using parceler with realm to pass data from activity to service.
i have few restrictions of realm and parceler
Restrictions
There are some important restrictions to be aware of when using Parceler:
If you model contains a RealmList you need to register a special adapter.
Once an object has been parcelled, it becomes detached from Realm and at this point behaves like an unmanaged object containing a snapshot of the data.Further changes to this object will not be persisted in Realm
for rule 1 i have register a special adapter for it , but for rule 2 i have a doub that at what point realm got deatched
is it at the time of annoting a class i.e. using
#Parcel(value = org.parceler.Parcel.Serialization.BEAN, analyze = { VisitInfo.class })
or at the time of unwrapping and wrapping
RequestInfo requestInfo = Parcels.unwrap(intent.getParcelableExtra("visitData"));

It becomes an unmanaged copy when you call Parcels.wrap() in the first place.
Realm by default expects you to send the primary key of the object over in the intent, and to requery it in the other Activity.

Related

Kotlin Firebase Parsing Duplication

So I have a Game object that has an init block where I setup the object and upload to the Firebase Firestore. Then when I'm listening for changes in that object I have to convert the DocumentSnapshot to a Game object.
game = snapshot.toObject(Game::class.java)
Pretty simple. The problem is is that this calls the init block of my Game class and uploads another game object. Is there a way I can avoid calling the init block while doing this? Thanks!
When you use automatic field mapping like this, the convention is that you should use a class definition that contains only the fields you want to map, and nothing else. Objects that have only getters and setters for properties are called JavaBeans, and their sole purpose is to store data. These objects must define a default no-arg constructor.
If you have additional logic that works with your Game object, that should go in a different class. It's better design to keep your data separate from the logic that works with the data (as you have discovered).
Move your init code to a constructor, which you can call when you're creating an instance of your Game class and you want it to upload the game object.

firebase persist data with circular reference

I've a simple data that i want to persist on firebase.
This data is a domain class for my relational model (i started with a relational model and now im deciding whenever or not migrate to firebase, but for awhile im working with both... or trying to)
To persist a new instance if my class on firebase i need to do:
Map<String, Object> firebase = new HashMap<String, Object>();
firebase.put("raffleDate", this.giveaway.getRaffleDate());
firebase.put("thumbnailUrl", this.giveaway.getThumbnailUrl());
firebase.put("mustFollowList", this.giveaway.getMustFollowList());
firebase.put("owner", this.giveaway.getOwner());
firebase.put("amountFriendsToIndicate", this.giveaway.getAmountFriendsToIndicate());
firebase.put("mediaId", this.giveaway.getMediaId());
((App) getApplication()).getFirebase().child("giveaways").child(this.giveaway.getMediaId()).setValue(firebase);
because besides these fields Giveaway has one last other field which has a circular reference to itself
#ToMany(referencedJoinProperty = "raffle")
#Expose(deserialize = false, serialize = false)
private List<UserOnGiveaway> attendantsTickets;
This field maps the relatioship between user and its giveaways, UserOnGiveaway class has a reference to User and Giveaway so when i try to persist i get a very long non compreensive error that I can just guess is due some stackoverflow because of the circular reference
The thing is I DONT REALLY CARE ABOUT PERSISTING THIS FIELD, in my actual "hybrid" archtecture i'm using firebase only to persist data shared among users, individual user data is being stored locally on android sqlite
So i would like to know is there any way i can annotate this field to force firebase ignore it?
or is there any parameter is can set on firebase call to do it?
PLEASE do not suggest transient as it will also affect my ORM
PLEASE2 do not suggest changes on domain since i'm giving a try to firebase i wont make any structural changes before decide for it.
thanks
You can use the #Exclude annotation on a field or getter/setter method to omit it from serialization with the Firebase SDK.

Realm Android: what is mean by isValid(), isLoaded(), isManaged()?

In Realm there are three methods isValid(), isLoaded(), isManaged().
I want to know which method should used when?
isValid
public final boolean isValid()
Checks if the RealmObject is still valid to use i.e., the RealmObject hasn't been deleted nor has the Realm been closed. It will always return true for unmanaged objects.
Two things invalidate a RealmObject:
- closing the Realm instance it belongs to
and deleting the object on any thread (if you're on an auto-updating
looper thread)
isLoaded
public final boolean isLoaded()
Checks if the query used to find this RealmObject has completed.
Async methods like RealmQuery.findFirstAsync() return an RealmObject that represents the future result of the RealmQuery. It can be considered similar to a Future in this regard.
Once isLoaded() returns true, the object represents the query result even if the query didn't find any object matching the query parameters. In this case the RealmObject will become a "null" object.
isManaged
public static boolean isManaged(E object)
Checks if this object is managed by Realm. A managed object is just a wrapper around the data in the underlying Realm file. On Looper threads, a managed object will be live-updated so it always points to the latest data. It is possible to register a change listener using addChangeListener(RealmModel, RealmChangeListener) to be notified when changes happen. Managed objects are thread confined so that they cannot be accessed from other threads than the one that created them.
Instances of Realm objects can be either managed or unmanaged.
Managed objects are persisted in Realm, are always up to date and thread confined. They are generally more lightweight than the unmanaged version as they take up less space on the Java heap.
Unmanaged objects are just like ordinary Java objects, they are not persisted and they will not be updated automatically. They can be moved freely across threads.
More info refer:https://realm.io/docs/java/4.3.3/api/io/realm/RealmObject.html
FROM DOCS
isValid()
Checks if the RealmObject is still valid to use i.e., the RealmObject hasn't been deleted nor has the Realm been closed. It will always return true for unmanaged objects.
Note that this can be used to check the validity of certain conditions such as being null when observed.
EXAMPLE :
// With RealmObject
yourRealmObject.isValid();
isLoaded()
Checks if the query used to find this RealmObject has completed.
Returns:
true if the query has completed, false if the query is in progress.
3.
isManaged()
Checks if this object is managed by Realm. A managed object is just a wrapper around the data in the underlying Realm file. On Looper threads, a managed object will be live-updated so it always points to the latest data. It is possible to register a change listener using addChangeListener(RealmModel, RealmChangeListener) to be notified when changes happen. Managed objects are thread confined so that they cannot be accessed from other threads than the one that created them.
If this method returns false, the object is unmanaged. An unmanaged object is just a normal Java object, so it can be parsed freely across threads, but the data in the object is not connected to the underlying Realm, so it will not be live updated.

Android: how to keep realmlist updated in the UI

I have a recyclerview which shows a list of students.
All of the students are held in a realmlist in the adapter.
When the user can ask for a data refresh, than the server sends the list of students back to the user.
What i am doing now is to download all of the information from the server , store it in the db , than retrieving it from the database(via realmresults) and than converting the realmresult to realmlist.
My question is how to properly update the UI?
I have seen in the documentation that realmlist have a managed mode where they are updating the ui automatically..
What is this managed mode? What does it means?
How do i use the realmlist to keep it in a managed state?
And what is the right way(aka best practice) to use realmlists?
Note that i cannot hold my information as realmresult directly because im performing some manipulation on the data that i dont want it to be saved.
Managed Object vs. Standalone
The standalone RealmObject/RealmList is created through the Object's constructor or the Realm.copyFromRealm() method. The data accessing in the standalone object won't go through the underline storage engine, instead, it behaves just like normal object. So the standalone object won't be refreshed when data changes. Examples for standalone object:
MyModel myModel = new MyModel(); // Standalone
MyModel model = realm.where(MyModel.class).findFirst(); // This is managed object.
MyModel standaloneModel = realm.copyFromRealm(model); // The returned value is standalone object.
MyList myList = new MyList(); // Standalone
The managed RealmObject/RealmList are accessing data though Realm's underlying storage engine. They are created when you do query from Realm, or the return from the copyToRealm() (and its variant methods). Like:
MyModel model = realm.where(MyModel.class).findFirst();
MyModel model = new MyModel(); // This is a standalone object.
model = realm.copyToRealm(modle); // The returned value is managed by Realm now.
MyList myList = realm.where(MyModel.class).findFirst().getMyList();
How to properly update the UI
The suggestion is using Realm's change listeners. See https://realm.io/docs/java/latest/#notifications
And what is the right way(aka best practice) to use RealmList?
This is a bit confusing, but Realm is introducing RealmCollection into the next major release (v0.89.0). See https://github.com/realm/realm-java/pull/2345.
Note that i cannot hold my information as realmresult directly because im performing some manipulation on the data that i dont want it to be saved.
If the RealmList is in managed mode, the data changes will be saved as well. If you don't want some data to be saved, you could consider to use #Ignore annotation on those fields. See https://realm.io/docs/java/latest/#ignoring-properties
Update on 04072016
RealmList vs. RealmResults:
RealmList is a list of RealmObject saved as a field of a RealmObject. It represents the one-to-many relationship in Realm.
RealmResults is the results of query.
Both of them (if RealmList in managed-mode) will be auto-refreshed when data changes.
You can get a RealmResults from a RealmList by RealmList.where() like:
RealmResults results = myRealmList.where().findAll();
This answer will be a bit out-of-date after Realm v0.89.0 released, because of new RealmCollection.

Realm or Paper for JPA in Android?

I'm developing an Android app with Android Annotations. For persistence, I firstly used a Content Provider (very complex) on top of SQLite. Then, I discovered Realm. It seemed very cool until I had to be notified for insertions to make my RecyclerView dynamic. To be notified of insertions, I made a singleton class I called RealmProxy with a proxy method for copyToRealm(), and an interface to implement to be a RealmListener. I called registered listeners in my copyToRealm() method passing them the added RealmObject, so I could populate my SortedList (support library list designed for RecyclerView) RecyclerView Adapter. I also used my RealmListener interface to send new Objects over network as soon as they are saved.
After compiling and running, I got and IllegalStateException (Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.) because I get the Realm instance from UI thread but I send them over network in a background thread obviously. Why do I get this error ? Whenever my JSON serialization library LoganSquare, based on Jackson calls a getter on my RealmObject in the background to send over network, this exception is thrown. This made me hate Realm thread policy and the fact that fine grained notifications aren't built-in. Also, Realm doesn't allow me to define any custom method. I can't even implement Comparable in a Realm Object.
When I saw Paper (thanks to Android Arsenal and Pushbullet) today, I was very interested in a no headaches JPA solution. It seems very simple, without restriction for Lists, Maps, and any class not extending a special class (Realm requires extending RealmObject and using RealmList instead of generic List which my json<>java didn't liked, forcing me to copy lists).
EDIT:
I discovered SnappyDB today. It uses the same serialization library (Kryo) as Paper, it seems to be very similar to Paper, with more features for keys management.
So my question is the following:
Should I search for workarounds and continue to use Realm, if yes, which workarounds, or should I use Paper, or SnappyDB instead ? Did anyone used Paper or SnappyDB for android?
All the best
If your question is about how to update your Object in UI thread when it gets changed in background, it is actually quite simple.
For example in your UI thread you can do this:
private Dog dog;
private RealmChangeListener listener = new RealmChangeListener() {
#Override
// This will be called when the commitTransaction gets called
// in the background thread
public void onChange() {
// It would changed to "EFG" automatically in next UI loop after
// you updated it in the background thread.
String name = dog.getName();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
dog = realm.where(Dog.class).equalTo("id", 42).findFirst();
// Assume it is "ABC" now
String name = dog.getName();
// Register the listener
realm.addChangeListener(listener);
}
And update the dog in th background service like:
// This realm will be a different instance created in this thread.
dog = realm.where(Dog.class).equalTo("id", 42).findFirst();
realm.beginTransaction();
dog.setName("EFG");
realm.commitTransaction();
The IllegalStateException is because of:
The only rule to using Realm across threads is to remember that Realm, RealmObject or RealmResults instances cannot be passed across threads. When you want to access the same data from a different thread, you should simply obtain a new Realm instance (i.e. Realm.getInstance(Context context) or its cousins) and get your objects through a query. The objects will map to the same data on disk, and will be readable & writeable from any thread!
See see doc here
And you probably need RealmBaseAdapter which can make building a ListView with Realm pretty easy. You can find example here.
JPA is not a solution, it's a definition for Java Persistence. Once you choose JPA, you need to find an implementation. In the Java world, the most widely used implementation is Hibernate. Also, you can use Hibernate ORM without using JPA.
On Android, OrmLite provides an implementation for a subset of JPA. But, as it's only a subset, you may as well skip JPA and use the equivalent Ormlite annotations. I use JPA implemented by Hibernate on my server apps, and Ormlite with no JPA on Android. I definitely recommend Ormlite.

Categories

Resources