2017-01-23 18 views
0

Короче говоря: я не знаю, почему мой RealmChangeListener не запускается по назначению при определенных обстоятельствах, и я ищу совет, почему RealmChangeListener не может работать.RealmChangeListener не выполняется при добавлении вскоре после асинхронной записи

Обновление: Я проверял, что RealmResults остается действительным = true; загружен = ложь. Если я выполнил RealmResults.load() после добавления слушателя изменений, он выведет неопределенный Throwing Exception 7 в журнале и BadVersionException, когда я пройду через источник Царства. Я думаю, что это исключение имеет смысл, асинхронная запись обновляет Realm, и поэтому запрос больше не работает. Однако как основной, так и начальный потоки запускаются как executeTransactionAsync, которые записываются в MainActivity, так и асинхронные запросы.

-

У меня есть MainActivity, в котором при нажатии на кнопку асинхронную запись будет выполняться.

У меня есть еще одна кнопка, которая открывает второе действие, которое отображает данные.

Второе действие использует ViewPager с фрагментом для каждой вкладки. Каждая вкладка имеет другой запрос.

Итак, теперь происходит следующее: я открываю второе действие, которое создает четыре фрагмента, не привязывая их к активности.

Затем выполняется запрос, передающий каждому RealmResults фрагменту, в котором будет установлен RealmChangeListener для отображения данных после его загрузки. Может ли быть так, что RealmChangeListener не работает, если фрагмент не привязан к Activity?

Во всяком случае, это метод, во фрагменте, который принимает RealmResults (созданный findAllAsyncSorted()) и предполагается, что для обновления данных на адаптере:

public void updateData(OrderedRealmCollection<Bean> realmCollection) { 
     Timber.v("Delegated data to fragment of adapter %s.", adapter); 
     this.data = (RealmResults<Bean>) realmCollection; 

    if (data.isLoaded()) { 
     Timber.d("Data is already loaded on adapter %s.", adapter); 
     adapter.updateDataManual(data); 
    } 

    if (!data.isValid()) { 
     Timber.e("Data is not valid."); 
    } 


    listener = new RealmChangeListener<RealmResults<Bean>>() { 
     @Override public void onChange(RealmResults<Bean> newResults) { 
      Timber.v("Change listener for manual data triggered: %d results in fragment for category %s and adapter %s.", 
       newResults.size(), category.toString(), adapter); 

      adapter.updateDataManual(newResults); 
     } 

     @Override protected void finalize() throws Throwable { 
      Timber.d("Finalizing change listener for adapter %s.", adapter); 
      super.finalize(); 
     } 
    }; 

    data.addChangeListener(listener); 

    MyTimer.setRepeatingCallback(() -> { 

     Timber.v("RealmResults in adapter %s are %s and %s, and the ChangeListener is %s.", 
      adapter, 
      data.isValid() ? "valid" : "invalid", 
      data.isLoaded() ? "loaded" : "not loaded", 
      listener); 

     return true; 
    }, 5000); 
} 

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

Все еще, из четырех RealmChangeListeners, только два или меньше (иногда ноль) триггера.

Обратите внимание, что это происходит только в том случае, если второе действие открывается вскоре после запуска асинхронной записи в MainActivity. Если я жду 2 секунды, все будет работать по назначению. Я убедился, что RealmChangeListener не является сборкой мусора, так как после выхода из приложения вызывается finalize(). Я понятия не имею, что может помешать слушателю работать. Есть ли что-то конкретное, на что я должен обратить внимание?

+0

Ваш объект 'data' выходит из области действия, когда метод заканчивается, поэтому он, скорее всего, является GC'ed. Вам нужно сохранить его в переменной класса. –

+0

@ChristianMelchior это тоже то, что я думал, но у него есть это.data = (RealmResults ) realmCollection; 'что означает, что результаты должны быть сохранены как переменная поля уже, но если он меняет их, тогда да – EpicPandaForce

+0

@ChristianMelchior Действительно я храню его в поле, доступ к которому можно получить только из опубликованного метода. Сейчас я пытаюсь написать тестовый класс, надеюсь, что смогу воспроизвести проблему там. – ferbeb

ответ

0

Вам необходимо иметь (сильную) ссылку на поле RealmResults<T>, чтобы вы не могли получить GC'd.

Если RealmResults получает GC'd, Realm больше не может его автоматически обновлять.

+0

Действительно, я храню его в поле, доступ к которому можно получить только из опубликованного метода. Сейчас я пытаюсь написать тестовый класс, надеюсь, что смогу воспроизвести проблему там. – ferbeb

+0

Кроме того, если вы закрываете экземпляр Realm, к которому принадлежит результирующий набор, тогда RealmChangeListeners для результатов, принадлежащих этому экземпляру Realm, больше не будут вызываться, потому что набор результатов недействителен. – EpicPandaForce

+0

Хм, я знаю, что вам трудно ребята отлаживать удаленно, не видя моего кода. Прямо сейчас я добавил таймер, который печатает следующие каждые пять секунд: 'Timber.v (« RealmResults в адаптере% s являются% s, а ChangeListener -% s. ». \t \t \t \t адаптер, data.isValid() ? «valid»: «invalid», listenener); «RealmResults являются действительными, а слушатель не собирает мусор. Я увижу, могу ли я воспроизвести его в инструментальном тесте, с первой попытки не воспроизвести проблему, к сожалению. – ferbeb