3

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

Louis CAD
  • 10,965
  • 2
  • 39
  • 58
  • May I ask what is your current problem with Realm? Is it about using Realm with RecyclerView across threads? Does this [similar question](http://stackoverflow.com/questions/28995380/best-practices-to-use-realm-with-a-recycler-view) help? – beeender Jul 06 '15 at 10:47
  • I get the described `IllegalStateException` when I use the same `RealmObject` in background and in UI. As my app is RESTful, I have to process networking in background, but i'm forced to re-query every time an object is added in Realm, which is unpractical and inefficient. – Louis CAD Jul 06 '15 at 12:11

2 Answers2

0

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.

beeender
  • 3,555
  • 19
  • 32
  • `RealmChangeListener` notifies for any change without giving any information about the change. I am using RecyclerView with SortedList and I need to get notified for insertions and deletions for a specific class (could even be a specific query). I don't want to update everything, loosing UI state each time any RealmObject changes. And I know the `IllegalStateException` source, but I can't get notified with the object passed in parameter because of this bad thread policy... – Louis CAD Jul 06 '15 at 14:48
  • That is true. We have an [open issue](https://github.com/realm/realm-java/issues/989) to track this on github. May I know what is your concern on the current implementation? Is it about receiving too many useless notifications? – beeender Jul 06 '15 at 14:52
  • I would like to be able to use RealmObjects across threads, and get any added or updated object in parameter. I need fine grained notifications because i'm using RecyclerView, which needs to be notified for insertions, updates and deletions to play content change animations well. – Louis CAD Jul 06 '15 at 15:20
0

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.

Christine
  • 5,617
  • 4
  • 38
  • 61