0

I have multiple fragments which are inside activities. I have called myAdapter in fragment onActivityCreate method.

I have read too many articles for realm performance improvements, adapter management, realm usage. I open the realm in resume and close it in pause. But sometimes my realm adapter has shown empty.When I've deleted closeRealm method, my adapter was running normally.

My error is because of overlapping openRealm and closeRealm from different adapters.

First adapter is opening -> openRealm--onCreate (time : 21:15) closing->closeRealm--onPause (time : 21:30:12)

Second adapter is opening -> openRealm--onCreate (time: 21:30:23) :: Above adapter is closing this realm

https://realm.io/docs/java/latest/#configuring-a-realm : It is important to note that Realm instances are thread singletons, meaning that the static constructor will return the same instance in response to all calls from a given thread.

I can manage realm for realm thread but can't manage ui thread. How can I create a different realm instance at the same time for ui thread? Please help me.

Realm adapter:

abstract class MyRealmRecyclerViewAdapter<T extends MyModel, VH extends RecyclerView.ViewHolder>
        extends RealmRecyclerViewAdapter<MyModel, VH> {

    protected Context context;
    private String TAG = MyRealmRecyclerViewAdapter.class.getSimpleName();

    protected Realm realm;

    MyRealmRecyclerViewAdapter(@Nullable OrderedRealmCollection<T> data, Realm realm) {

        super((OrderedRealmCollection<MyModel>) data, true, true);

        if (data != null && !data.isManaged()) {
            throw new IllegalStateException("Only use this adapter with managed RealmCollection, " +
                    "for un-managed lists you can just use the BaseRecyclerViewAdapter");
        }

        setRealm(realm);
        setHasStableIds(true);
    }

}

My fragment:

    public class MyFragment extends Fragment {

        private boolean isRealmAssignee = false;
        private Realm realm;

        @Override
        public void onActivityCreated(Bundle bundle) {
            super.onActivityCreated(bundle);

            Mylog.i(TAG, " onActivityCreated");
             try {
                myAdapter = new MyRealmRecyclerViewAdapter<>(this,
                        new MyQueries().getAllItems(getRealm()),getRealm());

                recyclerView.setAdapter(myAdapter);

            } catch (Exception e) {
                Mylog.printStackTrace(TAG + " initializeListAdapter error", e);
            }
        }

      @Override
        public void onResume() {
            super.onResume();

            Mylog.i(TAG, " onResume");

            setRealm();
        }

        @Override
        public void onPause() {

            super.onPause();

            Mylog.i(TAG, " onPause");
            closeRealm();
        }

        public void setRealm() {

            if (!isRealmAssignee && !RealmManager.checkRealm(realm)) {
                this.realm = RealmManager.open();
                isRealmAssignee = true;
            }
        }

        public Realm getRealm() {

            if (!RealmManager.checkRealm(realm)) {

                isRealmAssignee = false;
                setRealm();
            }

            return realm;
        }

        public void closeRealm() {

            RealmManager.close(realm);
            isRealmAssignee = false;
        }

RealmManager:

public class RealmManager {

    public synchronized static Realm open() {

        return Realm.getDefaultInstance();
    }

    public synchronized static void close(Realm mRealm) {

        if (checkRealm(mRealm)) {
            mRealm.close();
        }
    }

    public static boolean checkRealm(Realm realm) {
        return realm != null && !realm.isClosed();
    }
}
propoLis
  • 1,229
  • 1
  • 14
  • 48
  • I'm not sure what articles you were reading on Realm performance, but https://realm.io/docs/java/latest/#realm-instance-lifecycle would have been sufficient. – EpicPandaForce Jul 13 '18 at 22:05
  • please see my edited question and share example which is usage realm for multiple adapters – propoLis Jul 16 '18 at 11:28
  • 1
    For your use-case, i'd recommend this approach: https://github.com/Zhuinden/realm-monarchy/tree/831ab834ed304385143f0918d7694abc42421c7a/monarchy-example/src/main/java/com/zhuinden/monarchyexample/features/managed – EpicPandaForce Jul 16 '18 at 12:42

1 Answers1

1

The answer to your question would be to use a ThreadLocal<Realm>.

private final ThreadLocal<Realm> localRealms = new ThreadLocal<>();

/**
 * Opens a reference-counted local Realm instance.
 *
 * @return the open Realm instance
 */
public Realm openLocalInstance() {
    checkDefaultConfiguration();
    Realm realm = Realm.getDefaultInstance(); // <-- this could use input RealmConfiguration
    Realm localRealm = localRealms.get();
    if(localRealm == null || localRealm.isClosed()) {
        localRealms.set(realm);
    }
    return realm;
}

public Realm getLocalInstance() {
    Realm realm = localRealms.get();
    if(realm == null || realm.isClosed()) {
        throw new IllegalStateException(
                "No open Realms were found on this thread.");
    }
    return realm;
}

public void closeLocalInstance() {
    checkDefaultConfiguration();
    Realm realm = localRealms.get();
    if(realm == null || realm.isClosed()) {
        throw new IllegalStateException(
                "Cannot close a Realm that is not open.");
    }
    realm.close();
    // noinspection ConstantConditions
    if(Realm.getLocalInstanceCount(Realm.getDefaultConfiguration()) <= 0) {
        localRealms.set(null);
    }
}

And then you could use realmManager.openLocalInstance() and realmManager.closeLocalInstance() from onCreateView/onDestroyView to manage the lifecycle, while use realmManager.getLocalInstance() elsewhere on the given thread.


But it might just be easier to use findAllManaged* in my library named Monarchy which handles automatic Realm lifecycle management.

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
  • Very thanks. What should I do that closeThisRealm(realm) and how can I find inside localRealms – propoLis Jul 16 '18 at 15:51
  • AFAIK if you call `getInstance` twice then `realm1 == realm2`, and there's a reference counter that is increased. So no need to close specific instances of Realm, only number of times matters (and it occurs on the current thread, of course) – EpicPandaForce Jul 16 '18 at 16:03
  • at openLocalInstance 4.line : `if(localRealm != null && !localRealm.isClosed()) {localRealms.set(realm);}` It does not have to be this way otherwise it is true? – propoLis Jul 17 '18 at 06:41
  • It's just there for safety but generally. Generally it'll be `localRealm == null` if you use it when the Realm was closed and then you call `open`. – EpicPandaForce Jul 17 '18 at 09:08