Refreshing multiple Realm instances at once?

▼魔方 西西 提交于 2019-11-28 09:58:14

问题


I'm using a setup in which every Presenter that is a retained Fragment has its own Realm instance. However, this essentially means that these Realms are all on the main thread.

Now that also means, if I want to modify the Realm, I either need to do that on the main thread (which is okay for small data sets, but I don't really want to do that with large data sets), or I need to do it on a background thread, and refresh every Realm instance at once (which is possible with a simple event to the event bus).

public enum SingletonBus {
    INSTANCE;

    private static String TAG = SingletonBus.class.getSimpleName();

    private Bus bus;

    private boolean paused;

    private final Vector<Object> eventQueueBuffer = new Vector<>();

    private Handler handler = new Handler(Looper.getMainLooper());

    private SingletonBus() {
        this.bus = new Bus(ThreadEnforcer.ANY);
    }

    public <T> void postToSameThread(final T event) {
        bus.post(event);
    }

    public <T> void postToMainThread(final T event) {
        try {
            if(paused) {
                eventQueueBuffer.add(event);
            } else {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            bus.post(event);
                        } catch(Exception e) {
                            Log.e(TAG, "POST TO MAIN THREAD: BUS LEVEL");
                            throw e;
                        }
                    }
                });
            }
        } catch(Exception e) {
            Log.e(TAG, "POST TO MAIN THREAD: HANDLER LEVEL");
            throw e;
        }
    }

    public <T> void register(T subscriber) {
        bus.register(subscriber);
    }

    public <T> void unregister(T subscriber) {
        bus.unregister(subscriber);
    }

    public boolean isPaused() {
        return paused;
    }

    public void setPaused(boolean paused) {
        this.paused = paused;
        if(!paused) {
            Iterator<Object> eventIterator = eventQueueBuffer.iterator();
            while(eventIterator.hasNext()) {
                Object event = eventIterator.next();
                postToMainThread(event);
                eventIterator.remove();
            }
        }
    }
}

And

SingletonBus.INSTANCE.postToMainThread(new RealmRefreshEvent());

@Subscribe
public void onRealmRefreshEvent(RealmRefreshEvent e) {
    this.realm.refresh();
}

But assuming I have about 5-7 realm instances open on the main thread (as every presenter has its own open realm while they are not destroyed), I'm concerned about performance and/or memory usage.

So I guess I have two questions,

1.) Is it bad practice / heavily resource-intensive to have multiple Realm instances open on the main thread?

2.) How resource-intensive is it to update multiple Realms on the same thread with a global refresh event?


回答1:


Realm uses a ThreadLocal cache internally pr. Realm file so it is practically free to call Realm.getInstance() in every activity/fragment/presenter you have. The first call to Realm.getInstance() will cost a little as database has to be opened and the schema verified, but after that it just cost a cache lookup.

The cache is reference counted so the native resources will only be freed after all instances has been closed. This means it can be beneficial to keep at least one open instance around as long as possible.

This also means that when you update 1 of you open instances, they all get updated automatically.




回答2:


A possible way of having an open realm at all times while the application is active.

public class BaseActivity extends AppCompatActivity {
    private CustomApplication customApplication;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        customApplication = (CustomApplication)getApplication();
        if(savedInstanceState == null) {
            customApplication.incrementActivityCounter();
        }
    }

    @Override
    protected void onDestroy() {
        if(isFinishing()) {
            customApplication.decrementActivityCounter();
        }
        super.onDestroy();
    }
}

public class CustomApplication extends Application {
    public static final String TAG = CustomApplication.class.getSimpleName();

    private volatile int activityCounter = 0;

    private Realm realm;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "Application onCreate() called.");
        initializeRealm();
    }

    public void incrementActivityCounter() {
        if (activityCounter == 0) {
            Log.d(TAG, "Increment: Activity counter was 0, initializing Realm.");
            if(realm == null) {
                initializeRealm();
            }
        }
        activityCounter++;
        Log.d(TAG, "Increment: Activity counter incremented to " + activityCounter + ".");
    }

    public void decrementActivityCounter() {
        activityCounter--;
        Log.d(TAG, "Decrement: Activity counter decremented to " + activityCounter + ".");
        if(activityCounter == 0) {
            realm.close();
            realm = null;
            Log.d(TAG, "Decrement: Activity counter was 0, closed realm.");
        }
    }

    private void initializeRealm() {
        realm = Realm.getInstance(this);
        Log.d(TAG, "Realm initialized.");
    }

    public Realm getRealm() {
        return realm;
    }

    public int getActivityCounter() {
        return activityCounter;
    }

    public void setActivityCounter(int activityCounter) {
        this.activityCounter = activityCounter; //process death
    }
}

And then

public class BaseActivity
        extends AppCompatActivity {
   @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("activityCounter", ((CustomApplication) getApplication()).getActivityCounter());
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        int activityCounter = savedInstanceState.getInt("activityCounter");
        ((CustomApplication) getApplication()).setActivityCounter(activityCounter); //fix process death initializing activity counter to 0
        Log.d(TAG, "Reset activity counter in application after process death to [" + activityCounter + "]");
    }
}


来源:https://stackoverflow.com/questions/30549290/refreshing-multiple-realm-instances-at-once

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!