1

I am trying to update database on non UI thread, however changeListener registered on main thread (at the same time) sometimes not get called. Each Activity adds that listener when onStart method is called, and unregister on onStop.

Here is the simple application flow:

Activity1 contains a list of already create items. When user wants to add new item, Activity2 is launched. User fills all required fields and press add btn -> created item is added into local database with temporary ID, and job is added to queue to create that item on remote. After these two operations, Activit2 is closed (calling finish()) and user is back on Activity1 with list of all already created items (including the new one). Meanwhile, job for creating new item on remote is finished, and within its onRun() method, tmpID of created object is replaced with new one that was retrieved from server. However, at this point Activity1 do not get notified about change in database.

Activities register listener like this:

public Activity extends AppCompatActivity {

      private Realm mRealm;
      private RealmChangeListener listener = element -> Log.d("Called");

      @Override
      protected void onStart() {
          super.onStart();
          mRealm = Realm.getDefaultInstance();
          mRealm.addChangeListener(realmChangeListener);
      }

      @Override
      protected void onStop() {
          super.onStop();
          mRealm.removeChangeListener(realmChangeListener);
          mRealm.close();
      }          
 }

This is method of job, that is run on worker thread

 @WorkerThread
 public void onRun() {

     Response<ItemResponse> response = mAPI.createItem(text).execute();
     if(response.isSuccessful){
         Realm realm = Realm.getDefaultInstance();
         realm.executeTransaction(r ->{
             Item i = r.where(Item.class).equalTo("id", tmpID).findFirst();
             if(i != null){
                 i.id = response.body().id;
             }
         });
         realm.close();
         // At this point onChange() method of realmChangeListener should be fired
     }
}

On the other side, if I would stay on Activity2(not calling finish() after item is added into local DB) and wait until job get finished, onChange() method of RealmChangeListener is called properly...

Both of threads runs on the same process.

I am thankful for any suggestions

EDIT

Activity1 has a fragment attached to it, an that fragment contains list of items. Fragment then registers for listeners according to Best practises - Controlling the lifecycle of Realm instances within onStart and onStop callbacks.

@Override
public void onStart() {
    super.onStart();
    mRealm = Realm.getDefaultInstance();
    mRealm.addChangeListener(realmChangeListener);
}

@Override
public void onStop() {
    super.onStop();
    mRealm.removeChangeListener(realmChangeListener);
    mRealm.close();
}

Lifecycle of Fragment, when Activity2 is:

Launched

  • onPause

Closed using back button or by calling finish()

  • onStart
  • onResume

For some reason, when Activity2 is closed manually, using back button, realmChangeListener is called. However, if I close it using finish(), nothing happens ...

jpact
  • 1,042
  • 10
  • 23
  • 1
    Instead of using `onStart`/`onStop` maybe you should consider to use `onCreate`/`onDestory`. See http://stackoverflow.com/questions/6812003/difference-between-oncreate-and-onstart I think there is a chance, the activity 1's `onStart` is not called before data changes. – beeender Sep 01 '16 at 03:51
  • Yup, use `onCreate()`/`onDestroy()` combo instead of `onStart()`/`onStop()` – EpicPandaForce Sep 01 '16 at 04:03
  • Thanks for tips guys! For simplicity of question I used example with Activities, however Activity1 has a Fragment attached to it which shows that list... I'm sorry and should have had write it when asking a question, my bad.... Going to make a small edit – jpact Sep 01 '16 at 09:51
  • Question is edited! Looks like the fragment is just pushed on the backstack and then popped out as only onStart and onResume are called. However, why that difference between way of closing activities... I also tried to call finish() not immediately after insertion to local DB, but with delay about 1.5s, however, again - no difference. – jpact Sep 01 '16 at 09:53

1 Answers1

1

Finally, after a couple of hours I found out where the problem was...

Activity1 has a Fragment attached to it with list of items and that fragment listens for changes on realm database to update UI. When user wanted to add new item, Activity2 was launched and along with it a presenter, that was carrying about loading some stuff from local DB. That presenter was also listening on Realm DB.

And here is the problem: When user added new item and Activity2 was about to finish, close() method was called on presenter to clear the resources. One of the commands that were called within close() method, was mRealm.removeAllChangeListeners(). That wouldn't be a problem as Fragment from Activity1 registers its listener again in onStart() callback, but close() method on presenter was called AFTER onStart() on Fragment. So, basically it removed newly registered listener from fragment.

Again, thank you guys for your willingness! @beeender, @EpicPandaForce

jpact
  • 1,042
  • 10
  • 23