https://github.com/zhuinden/realm-book-example
This is an example rewrite of AndroidHive's messy tutorial, accompanying the following article on Realm.
https://github.com/zhuinden/realm-book-example
Last synced: about 2 months ago
JSON representation
This is an example rewrite of AndroidHive's messy tutorial, accompanying the following article on Realm.
- Host: GitHub
- URL: https://github.com/zhuinden/realm-book-example
- Owner: Zhuinden
- License: other
- Created: 2016-08-16T00:21:15.000Z (almost 9 years ago)
- Default Branch: master
- Last Pushed: 2017-12-15T20:06:59.000Z (over 7 years ago)
- Last Synced: 2025-04-01T15:41:08.875Z (3 months ago)
- Language: Java
- Homepage: https://medium.com/@Zhuinden/how-to-use-realm-for-android-like-a-champ-and-how-to-tell-if-youre-doing-it-wrong-ac4f66b7f149
- Size: 162 KB
- Stars: 80
- Watchers: 6
- Forks: 19
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# realm-book-example
This is a rewrite of a ["Realm tutorial" on Android Hive](http://www.androidhive.info/2016/05/android-working-with-realm-database-replacing-sqlite-core-data). 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:- using `begin/commitTransaction()` instead of `executeTransaction()`
- calling `refresh()` even though the Realm instance is freshly open
- the transactions are all done on the UI thread
- the Realm instance is never closedIt also uses outdated practices or is just not up-to-date information:
- `refresh()` doesn't even exist anymore, and even when it did, in this use-case it was not needed
- uses a Migration to pre-populate the database, even though `initialData()` exists now
- claims that `null` support for primitives isn't in, even though it was added in 0.83.0
- the code relies on `commitTransaction()` immediately updating the `RealmResults` and calling `adapter.notifyDataSetChanged()` manually, but that's not the case since 0.89.0 which means you need to add a change listener to the `RealmResults` (which `RealmRecyclerViewAdapter` does for you automatically)------------------------------
So with that in mind, this repository shows how to do these things right:
- uses `executeTransactionAsync()` on the UI thread
- uses `initialData()` to prepopulate the Realm
- uses `RealmManager` class (a bit stub-like because I'll have to make its content not static later) to manage number of open activities
- uses retained fragment to count open activity
- uses retained fragment to store presenter (oh, it actually has a "presenter" instead of just throwing everything in `OnClickListener`s)
- does not use `Application` subclass explicitly because of [Firebase Crash Reporting](https://firebase.google.com/docs/crash/android) for example creating multiple Application instances
- uses `RealmRecyclerViewAdapter` with asynchronous querySo yeah, this is the interesting class:
``` java
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.
``` java
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.
``` java
@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
``` java
recycler.setAdapter(new BooksAdapter(this, realm.where(Book.class).findAllAsync(), booksPresenter));
```
Where the adapter is a proper `RealmRecyclerViewAdapter`:``` java
public class BooksAdapter extends RealmRecyclerViewAdapter {
```
And the writes are from the UI thread to a background thread using `executeTransactionAsync()`, found in the presenter.``` java
Realm realm = RealmManager.getRealm();
realm.executeTransactionAsync(new Realm.Transaction() {
```