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.