2015-05-30 8 views
2

Я использую настройку, в которой каждый Presenter, который является сохраненным Fragment, имеет свой собственный экземпляр Realm. Однако это по существу означает, что эти Царства находятся в основном потоке.Обновление нескольких экземпляров Realm сразу?

Теперь это также означает, что если я хочу изменить Царство, мне нужно либо сделать это на основном потоке (что хорошо для небольших наборов данных, но я действительно не хочу этого делать с большими наборами данных), или мне нужно сделать это в фоновом потоке и обновить каждые Экземпляр Realm сразу (что возможно с помощью простого события на шину событий).

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(); 
      } 
     } 
    } 
} 

И

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

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

Но если предположить, у меня есть около 5-7 экземпляров области открытого в главном потоке (как каждый ведущие имеют свою собственную открытую область, пока они не уничтожены), я обеспокоен о производительности и/или использовании памяти.

Так что я думаю, у меня есть два вопроса,

1.) Это плохая практика/сильно ресурсоемкий иметь несколько экземпляров Realm открытых на основной нити?

2.) Насколько ресурсоемким является обновление нескольких Realms в одном потоке с помощью глобального события refresh?

ответ

2

Realm использует кеш ThreadLocal внутри pr. Realm, так что вы можете фактически позвонить Realm.getInstance() в каждом действии/фрагменте/презентаторе, который у вас есть. Первый вызов Realm.getInstance() будет стоить немного, поскольку база данных должна быть открыта, а схема проверена, но после этого она просто требует поиска в кеше.

Кэш относится к подсчету, поэтому исходные ресурсы будут освобождены только после закрытия всех экземпляров. Это означает, что полезно сохранить хотя бы один открытый экземпляр как можно дольше.

Это также означает, что при обновлении 1 из открытых экземпляров все они обновляются автоматически.

+0

Ах, в этом случае, я должен убедиться, что я обновляю только * один * экземпляр, так что я не называют 'Refresh()' метод N раз. Тем не менее, у меня есть доступ к одному царству за раз, я думаю, что вызов 'refresh()' не должен быть глобальным, просто вызывается одним экземпляром в основном потоке. Ухоженная! Спасибо за ответ :) – EpicPandaForce

+0

Подождите, означает ли это, что я могу просто дать runnable обработчику, который отправляет сообщения основному петлеучеру, который получает экземпляр realm, вызывает обновление, затем закрывает его - и обновляет * каждый * realm on основной поток? – EpicPandaForce

+1

Да, это должно работать, но мы уже делаем это для вас :). Если у вас есть данные, записывающие Realm в фоновый поток, он уже отправляет сообщение основному петлеучеру, запрашивая, чтобы все Realms обновлялись при совершении транзакции. Также здесь вызывается прослушивание onChange. –

2

Возможный способ наличия открытого пространства в любое время, пока приложение активно.

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 
    } 
} 

А потом

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 + "]"); 
    } 
} 
Смежные вопросы