0

On a button click I want to create a new SQLite database from two XML files. Using LoaderManager and AsyncTaskLoader seems to be appropriate for this.

The Fragment.onCreate() calls:

setRetainInstance(true);

When the button is clicked, my Fragment sets a flag that it is creating the database, changes the layout to show a ProgressBar and cancel button, and calls:

getLoaderManager().initLoader(0, extra, this);

The operation takes 12 seconds on my PC/Emulator. If I rotate the screen, the loader continues to call the Fragment's onLoaderProgressUpdate(int) (an interface callback method) and completes the creation of the database. But it never calls the onLoadFinished() method, where I can reset the layout, enable buttons and the action bar menu that require the database to be there.

I tried doing this in Fragment.onCreateView():

if (mCreatDBInProgress) {
    mBTN_CreateDB.setEnabled(false);
    mDBLayout.setVisibility(View.GONE);
    mProgressBarLayout.setVisibility(View.VISIBLE);
    getLoaderManager().restartLoader(0, null, this);
}

But it calls my onCreateLoader() method and starts the whole thing from scratch. This is a problem, since I have not called the method that deletes the database and goes through the process of determining what XML files to use for creating the database. The XML filenames are what I pass to that method in the Bundle arg.

I don't get why the ProgressBar callback method continues to work, but the AsyncTaskLoader can't call the onLoadFinished() method. LogCat shows that it did the deliverResult().

I tried to make the Bundle a member variable, so I could re-use it on the restartLoader() call. It start another asyncTaskLoader and my ProgressBar goes back and forth as both threads try to update it. Eventually, it gets an SQLConstraintException trying to add a row to the database that was already added by the first thread.

Peter O.
  • 32,158
  • 14
  • 82
  • 96
Rick Falck
  • 1,778
  • 3
  • 15
  • 19

2 Answers2

0

Well, suck me sideways! I came up with one more idea, and it worked!

Instead of calling restartoader() after the rotation, just call:

getLoaderManager().initLoader(0, mExtra, this);

For (whatever) reason, that causes the AsynTaskLoader to just continue with the first thread (instead of starting another) and relink to my Fragment for the onLoadFinished() call.

So:

initLoader() - reconnects the loader to your Fragment IF you call it with the same arguments (int, Bundle, this).

Rick Falck
  • 1,778
  • 3
  • 15
  • 19
0

I had the same problem, when after rotating screen onLoadFinished not called. I've seen a lot of answers but nothing really fix the issue. The only thing that helps is to simply add call to getLoaderManager() in onCreate method (it is called again after activity is recreated because of rotation). It's really fixed the issue for me:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    LoaderManager loaderMngr = getLoaderManager();
    Log.d(LOG_TAG, "" + loaderMngr);

And a little note about why I didn't just placed initLoader or restartLoader here: because Loader in my case is triggered after another event happens, so this was the only way to solve this problem for me. Originally idea got from here.

B-GangsteR
  • 2,534
  • 22
  • 34