Zhuinden / realm-book-example

This is an example rewrite of AndroidHive's messy tutorial, accompanying the following article on Realm.
https://medium.com/@Zhuinden/how-to-use-realm-for-android-like-a-champ-and-how-to-tell-if-youre-doing-it-wrong-ac4f66b7f149
Other
80 stars 19 forks source link

realm-book-example

This is a rewrite of a "Realm tutorial" on Android Hive. Unfortunately the tutorial is extremely outdated (uses 0.82.1 even though the version 3.5.0 is out!), the code is unstructured (Realm transactions inside a click listener inside a dialog created in a long click listener); and it also misuses Realm quite heavily:

It also uses outdated practices or is just not up-to-date information:


So with that in mind, this repository shows how to do these things right:

So yeah, this is the interesting class:

public class RealmManager {
    static Realm realm;

    static RealmConfiguration realmConfiguration;

    public static void initializeRealmConfig(Context appContext) {
        if(realmConfiguration == null) {
            setRealmConfiguration(new RealmConfiguration.Builder(appContext).initialData(new RealmInitialData())
                    .deleteRealmIfMigrationNeeded()
                    .build());
        }
    }

    public static void setRealmConfiguration(RealmConfiguration realmConfiguration) {
        RealmManager.realmConfiguration = realmConfiguration;
        Realm.setDefaultConfiguration(realmConfiguration);
    }

    private static int activityCount = 0;

    public static Realm getRealm() {
        return realm;
    }

    public static void incrementCount() {
        if(activityCount == 0) {
            if(realm != null) {
                if(!realm.isClosed()) {
                    realm.close();
                    realm = null;
                }
            }
            realm = Realm.getDefaultInstance();
        }
        activityCount++;
    }

    public static void decrementCount() {
        activityCount--;
        if(activityCount <= 0) {
            activityCount = 0;
            realm.close();
            Realm.compactRealm(realmConfiguration);
            realm = null;
        }
    }
}

Which has its RealmConfiguration initialized in Activity.onCreate(), and the Realm instance itself is opened with RealmManager.incrementCount() from the retained fragment's constructor.

public class BooksScopeListener extends Fragment {
    BooksPresenter booksPresenter;

    public BooksScopeListener() {
        setRetainInstance(true);
        RealmManager.incrementCount();
        booksPresenter = new BooksPresenter();
    }

    @Override
    public void onDestroy() {
        RealmManager.decrementCount();
        super.onDestroy();
    }

    public BooksPresenter getPresenter() {
        return booksPresenter;
    }
}

Which is created in the Activity.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        RealmManager.initializeRealmConfig(getApplicationContext());
        super.onCreate(savedInstanceState);
        BooksScopeListener fragment = (BooksScopeListener) getSupportFragmentManager().findFragmentByTag("SCOPE_LISTENER");
        if(fragment == null) {
            fragment = new BooksScopeListener();
            getSupportFragmentManager().beginTransaction().add(fragment, "SCOPE_LISTENER").commit();
        }
        realm = RealmManager.getRealm();
        booksPresenter = fragment.getPresenter();

The adapter is set up like this

recycler.setAdapter(new BooksAdapter(this, realm.where(Book.class).findAllAsync(), booksPresenter));

Where the adapter is a proper RealmRecyclerViewAdapter:

public class BooksAdapter extends RealmRecyclerViewAdapter<Book, BooksAdapter.BookViewHolder> {

And the writes are from the UI thread to a background thread using executeTransactionAsync(), found in the presenter.

    Realm realm = RealmManager.getRealm();
    realm.executeTransactionAsync(new Realm.Transaction() {