0

I'm fetching data in my activity that is needed by several fragments. After the data is returned, I create the fragments. I was doing this via an AsyncTask, but it led to occasional crashes if the data returned after a screen rotation or the app is backgrounded.

I read up and thought the solution to this was instead using an AsyncTaskLoader. Supposedly it won't callback if your activity's gone, so those errors should be solved. But this now crashes every time because "Can not perform this action (add fragment) inside of onLoadFinished".

How am I supposed to handle this? I don't want my fragments to each have to fetch the data, so it seems like the activity is the right place to put the code.

Thanks!

Edit 1

Here's the relevant code. I don't think the problem is with the code per-se, but more of my whole approach. The exception is pretty clear I shouldn't be creating fragments when I am. I'm just not sure how to do this otherwise.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getSupportLoaderManager().initLoader(BREWERY_LOADER, null, this).forceLoad();
}

//================================================================================
// Loader handlers
//================================================================================

@Override
public Loader<Brewery> onCreateLoader(int id, Bundle args) {
    int breweryId = getIntent().getIntExtra(EXTRA_BREWERY_ID, -1);
    return new BreweryLoader(this, breweryId);
}

@Override
public void onLoadFinished(Loader<Brewery> loader, Brewery data) {
    if (data != null) {
        onBreweryReceived(data);
    } else {
        onBreweryError();
    }
}

@Override
public void onLoaderReset(Loader<Brewery> loader) {

}

...

protected void onBreweryReceived(Brewery brewery) {
    ...
    createFragments();
}

...

protected void createFragments() {
    FragmentManager fm = getSupportFragmentManager();

    //beers fragment
    mBeersFragment = (BreweryBeersFragment)fm.findFragmentById(R.id.beersFragmentContainer);

    if (mBeersFragment == null) {
        mBeersFragment = new BreweryBeersFragment();
        fm.beginTransaction()
                .add(R.id.beersFragmentContainer, mBeersFragment)
                .commit();

        Bundle beersBundle = new Bundle();
        beersBundle.putInt(BreweryBeersFragment.EXTRA_BREWERY_ID, mBrewery.getId());
        mBeersFragment.setArguments(beersBundle);
    }
}

Edit 2

My new strategy is to use an IntentService with a ResultReceiver. I null out callbacks in onPause so there's no danger of my activity being hit when it shouldn't be. This feels a lot more heavy-handed than necessary, but AsyncTask and AsyncTaskLoader neither seemed to have everything I needed. Creating fragments in those callback methods doesn't seem to bother Android either.

Dennis
  • 1,697
  • 2
  • 12
  • 15

1 Answers1

0

From the MVC (Model -- View -- Controller) viewpoint, both the Activity and its fragments are Controller, while it is Model that should be responsible for loading data. As to the View, it is defined by the layout xml, you can define custom View classes, but usually you don't.

So create a Model class. Model is responsible for what must survive a screen turn. (Likely, it will be a static singleton; note that Android can kill and re-create the process, so the singleton may get set to null.) Note that Activities use Bundles to send data to themselves in the future.

Community
  • 1
  • 1
18446744073709551615
  • 16,368
  • 4
  • 94
  • 127
  • I am keeping data in a singleton model. My problem though is I need to fetch the data first in my activity so both of my fragments have access to it. This is the part that has me stumped- how to delay creation of them until their necessary data is fetched. – Dennis Feb 02 '15 at 05:47
  • Your activity will set a callback and call `theModelSingleton.startFetchingData()`. After the data-fetching function calls the callback, you will be able to either create fragments or (better) change them to reflect the fetched data. Do not put too much application logic into the fragments, they are _Controllers_! – 18446744073709551615 Feb 02 '15 at 07:26