After two long two days of scratching my head and altruistic engagement from Psklin, I painted myself a picture of what was wrong. My activity A is actually much more complicated. It uses a ViewPager with a PagerAdapter with a list of instances. First, I created these components in the onCreate () method like this:
@Override public void onCreate(Bundle savedInstanceState) { ... super.onCreate(savedInstanceState); // 1 .ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager); ... viewPager.setAdapter( new MyPagerAdapter() ); viewPager.setOnPageChangeListener(this); */ ... // 2. Loader getSupportLoaderManager().initLoader(LOADER_ID, null, this); ... // 3. CursorAdapter myCursorAdapter = new MyCursorAdapter( this, R.layout.list_item_favorites_history, null, 0); }
Somewhere along the line, I noticed that this is the wrong order of creation. Why this did not cause an error because PagerAdapter.instantiateItem () is called aftter onCreate (). I do not know why and how this caused the initial problem. Something may not have connected correctly to lists, adapters, and content watchers. I did not delve into this.
I reordered:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... // 1. CursorAdapter myCursorAdapter = new MyCursorAdapter( this, R.layout.list_item_favorites_history, null, 0); ... // 2. Loader getSupportLoaderManager().initLoader(LOADER_ID, null, this); ... // 3 .ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager); ... viewPager.setAdapter( new MyPagerAdapter() ); viewPager.setOnPageChangeListener(this); */ ... }
This magic made it work in about 75% of cases. When I examined the output of CatLog, I noticed that ActivityA (). OnStop () is called at different times. When it works, it is called late, and I see in logcat that onLoadFinished () is executing. Sometimes ActivityA.onStop () is executed immediately after the request, and then onLoadFinished () is not called at all. This leads me to posting in my DeeV jas answer that cursors are not registered with ContentResolver. It may be so. What made things somehow reveal was the fact that a simple pskink demonstrator insisted on working, and my application was not there, although they were the same in key points. This caught my attention on asynchronous things and my onCreate () method. Actually my ActivityB is complicated, so it gives enough time to stop ActivityA. What I also noticed (and it made it harder to sort) was that if I ran my 75% version in debug mode (without breakpoints), then the success rate would drop to 0. ActivityA will stop until the download is complete cursor, so my onLoadFinished () is never called, and the lists are not updated.
Two key points:
- Somehow the order of creating odPager, CursorAdapter and CursorLoader is important.
- ActivityA can be stopped (s) before the cursor is loaded.
But even that is not so. If I look at the simplified sequence, then I see that ActivityA.onStop () is executed before the content provider inserts the record. I do not see the request while ActivityB is active. But when I get back to ActivityA, you will get execeuted laodFinished () and the listview will update. Not so in my application. It always executes the request while still in ActivityB, why ??? This destroys my theory that onStop () is the culprit.
(Many thanks to pskink and DeeV)
UPDATE
After a lot of time on this problem, I finally nailed the cause of the problem.
Short description:
I have the following classes:
ActivityA - contains a list view populated via cursor loader. ActivityB - that changes data in database ContentProvider - content provider used for data manipulation and also used by cursorloader.
Problem:
After manipulating the data in ActivityB, the changes are not displayed in list mode in ActivityA. List view is not updated.
After I studied a lot and studied the traces of logcat, I saw that everything happens in the following sequence:
ActivityA is started ActivityA.onCreate() -> getSupportLoaderManager().initLoader(LOADER_ID, null, this); ContentProvider.query(uri) // query is executes as it should ActivityA.onLoadFinished() // in this event handler we change cursor in list view adapter and listview is populated ActivityA starts ActivityB ActivityA.startActivity(intent) ActivityB.onCreate() -> ContentProvider.insert(uri) // data is changed in the onCreate() method. Retrieved over internet and written into DB. -> getContext().getContentResolver().notifyChange(uri, null); // notify observers ContentProvider.query(uri) /* We can see that a query in content provider is executed. This is WRONG in my case. The only cursor for this uri is cursor in cursor loader of ActivityA. But ActivityA is not visible any more, so there is no need for it observer to observe. */ ActivityA.onStop() /* !!! Only now is this event executed. That means that ActivityA was stopped only now. This also means (I guess) that all the loader/loading of ActivityA in progress were stopped. We can also see that ActivityA.onLoadFinished() was not called, so the listview was never updated. Note that ActivityA was not destroyed. What is causing Activity to be stopped so late I do not know.*/ ActivityB finishes and we return to ActivityA ActivityA.onResume() /* No ContentProvider.query() is executed because we have cursor has already consumed notification while ActivityB was visible and ActivityA was not yet stopped. Because there is no query() there is no onLoadFinished() execution and no data is updated in listview */
Thus, the problem is not that ActivityA is stopped to the end, but that it is stopped until late. The data is updated and notified somewhere between the creation of the ActivityB and the stop of the ActivityA. The solution is to force the bootloader in ActivityA to stop loading immediately before starting ActivityB.
ActivityA.getSupportLoaderManager().getLoader(LOADER_ID).stopLoading();
This stops the bootloader, and (I think again) prevents the cursor from consuming notification while the activity is in the above uncertainty state. Now the sequence of events:
ActivityA is started ActivityA.onCreate() -> getSupportLoaderManager().initLoader(LOADER_ID, null, this); ContentProvider.query(uri)
It was the most elegant solution I could find. No need to reboot bootloaders, etc. But still, I would like to hear a comment on this issue from someone with a deeper understanding.