Reputation: 1954
I have a nested inner class that extends AsyncTask to run a db query in the background. In the post execute method I am calling a parent's method to update the view something like this
private class QueryRunner extends AsyncTask<Void,Void,Cursor> {
@Override
protected Cursor doInBackground(Void... voids)
{
return getContentResolver().query(LeadContentProvider.buildUri(app.getEntityId()),new String[]{LeadContentProvider._ID},null,null,LeadContentProvider.LEAD_STATUS_DATETIME +" desc");
}
@Override
protected void onPostExecute(Cursor c)
{
onCursorLoaded(c);
}
}
The onCursorLoaded method looks like:
private void onCursorLoaded(Cursor c)
{
mPagerAdapter = new LeadDetailsFragmentPagerAdaper(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.setCurrentItem(iIndex, false);
}
Most of the time this works fine - but some users have crashes with this stack trace:
java.lang.IllegalStateException: Must be called from main thread of process
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1392)
at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:431)
at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:139)
at android.support.v4.view.ViewPager.populate(ViewPager.java:804)
at android.support.v4.view.ViewPager.setAdapter(ViewPager.java:344)
at com.servicemagic.pros.activities.LeadDetails.onCursorLoaded(LeadDetails.java:205)
at com.servicemagic.pros.activities.LeadDetails.access$200(LeadDetails.java:25)
at com.servicemagic.pros.activities.LeadDetails$QueryRunner.onPostExecute(LeadDetails.java:196)
at com.servicemagic.pros.activities.LeadDetails$QueryRunner.onPostExecute(LeadDetails.java:170)
at android.os.AsyncTask.finish(AsyncTask.java:417)
at android.os.AsyncTask.access$300(AsyncTask.java:127)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:150)
at android.os.HandlerThread.run(HandlerThread.java:60)
So - why is the postExecute() method not called on the MainThread?
Upvotes: 3
Views: 3625
Reputation: 2930
I believe what @hovanessyan is getting at is that it is not safe to assume that the Fragment your AsyncTask was talking to when it launched may not be the same instance as when it finishes executing. Android may pause or even terminate the Fragment while the AsyncTask is running. That would explain why the problem is intermittent. It is only happening to users when their Fragment has been paused or destroyed and recreated.
This issue is discussed in this article. If you read items 2 and 3 in the article you will see how to address it. You are responsible for saving and restoring state as part of your Fragment life cycle. See android documentation of Fragment lifecycle.
Upvotes: 2
Reputation: 31463
the onPause() - onResume() loop does not go through onStart(). If you need this to be executed on the start of your Activity, put it in onResume(). You always go through onResume().
Upvotes: 2