Erum
Erum

Reputation: 790

Best way to use Realm database

using this code:

public class App extends Application {
            private static App instance;

            @Override
            public void onCreate() {
                super.onCreate();
                initRealmDB();
            }

            private void initRealmDB() {
                instance = this;
                Realm.init(this);
                RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().modules(new SimpleRealmModule()).name("RealmSample.realm").build();
                Realm realm = null;
                try {
                    realm = Realm.getInstance(realmConfiguration);
                    realm.setDefaultConfiguration(realmConfiguration);
                } finally {
                    if (realm != null) {
                        realm.close();
                    }
                }
            }
    }

**In use:**

    Realm realm = Realm.getDefaultInstance();
            RealmResults<OrganizationModelClass> results = realm.where(OrganizationModelClass.class).findAll();
            if(realm.isInTransaction())
            {
                realm.cancelTransaction();
            }
            realm.beginTransaction();
            if (results != null) {
                if(membershipList != null)
                {
                    membershipList.clear();
                }
                for (int i = 0; i < results.size(); i++) {
                    Log.d(OrganizationActivity.class.getName(), " i :" + results.get(i).getCurrent_membership_uuid());
    }
    }

Is this best way to use? Should i use singleton approach? If there is another good approach to fulfill this task, please share with me. i followed this https://dzone.com/articles/realm-practical-use-in-android but this code is not working with this dependency: classpath "io.realm:realm-gradle-plugin:3.3.1"

Realm realm = Realm.getInstance(SimpleRealmApp.getInstance());

Upvotes: 2

Views: 756

Answers (2)

adarsh
adarsh

Reputation: 531

public RealmController(Context context) {
    realm = Realm.getDefaultInstance();
}


public static RealmController with(Activity activity) {

    if (instance == null) {
        instance = new RealmController(activity.getApplication());
    }
    return instance;
}


public static RealmController with(Application application) {

    if (instance == null) {
        instance = new RealmController(application);
    }
    return instance;
}

public static RealmController getInstance() {
    if (instance == null) {
        instance = new RealmController(SysApplication.getAppContext());
    }
    return instance;

}

Upvotes: 0

EpicPandaForce
EpicPandaForce

Reputation: 81539

Is this best way to use?

No

Realm realm = Realm.getDefaultInstance(); // <-- opens Realm
        RealmResults<OrganizationModelClass> results = realm.where(OrganizationModelClass.class).findAll();
        if(realm.isInTransaction())
        {
            realm.cancelTransaction(); // <-- what if that transaction was important?
        }
        realm.beginTransaction();
        if (results != null) {
            if(membershipList != null)
            {
                membershipList.clear(); // <-- ??
            }
            for (int i = 0; i < results.size(); i++) {
                Log.d(OrganizationActivity.class.getName(), " i :" + results.get(i).getCurrent_membership_uuid()); // <-- if the result set was modified here because of the transaction, then the RealmResults will update, and you'll skip elements
}
           // <-- where is the commit?
} // <-- where is realm.close()?

Instead

try(Realm r = Realm.getDefaultInstance()) {
    r.executeTransaction((realm) -> { // AS 3.0+ desugar
        RealmResults<OrganizationModelClass> results = realm.where(OrganizationModelClass.class).findAll(); // <-- get in transaction
        for (OrganizationModelClass model : results) { // uses snapshot() internally
           Log.i(model.getClass().getName(), getCurrentMembershipUuid());
        }
    }
} // <-- auto-close because of try-with-resources

Should i use singleton approach?

Realm instances you open with getInstance()/getDefaultInstance() are thread-local and reference counted, so it is NOT suitable for being used as a singleton across the application. You need to open thread-local instances.

So on UI Thread, based on documentation:

// Setup Realm in your Application
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Realm.init(this);
        RealmConfiguration realmConfiguration = new RealmConfiguration.Builder()
             //.deleteIfMigrationNeeded()
             .migration(new MyMigration())
             .build();
        Realm.setDefaultConfiguration(realmConfiguration);
    }
}

// onCreate()/onDestroy() overlap when switching between activities.
// Activity2.onCreate() will be called before Activity1.onDestroy()
// so the call to getDefaultInstance in Activity2 will be fast.
public class MyActivity extends Activity {
    private Realm realm;
    private RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        realm = Realm.getDefaultInstance();

        setContentView(R.layout.activity_main);

        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        recyclerView.setAdapter(
            new MyRecyclerViewAdapter(this, realm.where(MyModel.class).findAllSortedAsync(MyModelFields.ID)));

        // ...
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        realm.close();
    }
}

// Use onCreateView()/onDestroyView() for Fragments.
// Note that if the db is large, getting the Realm instance may, briefly, block rendering.
// In that case it may be preferable to manage the Realm instance and RecyclerView from
// onStart/onStop instead. Returning a view, immediately, from onCreateView allows the
// fragment frame to be rendered while the instance is initialized and the view loaded.
public class MyFragment extends Fragment {
    private Realm realm;
    private RecyclerView recyclerView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        realm = Realm.getDefaultInstance();

        View root = inflater.inflate(R.layout.fragment_view, container, false);

        recyclerView = (RecyclerView) root.findViewById(R.id.recycler_view);
        recyclerView.setAdapter(
            new MyRecyclerViewAdapter(getActivity(), realm.where(MyModel.class).findAllSortedAsync(MyModelFields.ID)));

        // ...

        return root;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        realm.close();
    }
}

For background thread, see the docs:

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        try (Realm realm = Realm.getDefaultInstance()) {
            // No need to close the Realm instance manually
        }
    }
});

thread.start();

If you want to use Realm as a singleton, you have to use a class that can increment, decrement, and get instance without incrementing ref count for thread local Realms, kinda like this experiment here.

Upvotes: 2

Related Questions