简体   繁体   中英

How to prevent Loader from restarting during screen orientation change? - Android

I have an activity that presents a list of recipes in a RecyclerView. The computation of the items is costly, so I use a loader to populate the RecyclerView and that loader caches the data to prevent it from repeating the computation.

When I rotate the screen after the list of recipes is shown it behaves well (ie does not repeat the computation). But when i rotate the screen during the computation the loader starts computing again from beginning (so, eg, if i am rotating the screen every 5 seconds it never gets to show anything, because the computation takes about 12 seconds). Also, if i click on a recipe, launching a new activity, then rotate the screen and then click to go back to my recipe list activity, the loader starts computing everything again.

Is this an accepted behavior for an app? How can i prevent these repeated computations from happening?

My onCreate uses the loader with this line:

getSupportLoaderManager().initLoader(RECIPES_LOADER_ID, null, this);

My activity overrides the loader callbacks this way:

@NonNull
@Override
public Loader<List<Recipe>> onCreateLoader(int id, @Nullable Bundle args) {
    return new RecipesLoader(this, /* other parameters here */);
}

@Override
public void onLoadFinished(@NonNull Loader<List<Recipe>> loader, List<Recipe> data) {
    inventingTextView.setVisibility(View.INVISIBLE);
    inventingProgressBar.setVisibility(View.INVISIBLE);
    if (data != null) {
        recipesAdapter.updateRecipes(data);
    }
}

@Override
public void onLoaderReset(@NonNull Loader<List<Recipe>> loader) {
    recipesAdapter.updateRecipes(null);
}

My RecipesLoader is a static nested class inside my activity:

private static class RecipesLoader extends AsyncTaskLoader<List<Recipe>> {

    private List<Recipe> recipes = null;
    private /* other member variables here */

    public RecipesLoader(@NonNull Context context, /* other parameters here */) {
        super(context);
        /* initializing member variables here */;
    }

    @Override
    protected void onStartLoading() {
        super.onStartLoading();
        if (recipes != null) {
            deliverResult(recipes);
        } else {
            forceLoad();
        }
    }

    @Nullable
    @Override
    public List<Recipe> loadInBackground() {
        return /* costly computation here */
    }

    @Override
    public void deliverResult(@Nullable List<Recipe> data) {
        recipes = data;
        super.deliverResult(data);
    }
}

First of all, please consider detecting when user reaches the end of the list and then contact the server so the overall loading cost will be decreased.

Anyway, here is the possible solution:

MainActivity

public class MainActivity extends Activity {

    private List<Recipe> recipes;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);

        // initialize layout here

        restoreState(savedInstanceState);   
    }

    public void restoreState(Bundle state) {
        if(state == null) {
            // this is the first time activity is created
            recipes = new RecipesLoader().loadInBackground();
        }else {
            // configuration has been changed (e.g. device rotated)
            recipes = state.getSerializable("recipes");     
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle stateToSave) {
        super.onSaveInstanceState(stateToSave);

        stateToSave.putSerializable("recipes", recipes);
    }
}

Recipe

public class Recipe implements Serializable {
    // must implement Serializable because it will be passed through Intent

    . . .
}

By the way, you can take a look at chapter 19 in "The Busy Coder's Guide to Android Development" that explains how to handle rotation changes.

对于该活动,请在android Menifest文件中设置android:configChanges=orientation

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM