【问题标题】:How to prevent Loader from restarting during screen orientation change? - Android如何防止加载器在屏幕方向更改期间重新启动? - 安卓
【发布时间】:2018-04-17 18:53:03
【问题描述】:

我有一个在 RecyclerView 中显示食谱列表的活动。项目的计算成本很高,所以我使用加载器来填充 RecyclerView,并且加载器缓存数据以防止它重复计算。

当我在显示食谱列表后旋转屏幕时,它表现良好(即不重复计算)。但是,当我旋转屏幕计算期间,加载程序从头开始再次计算(例如,如果我每 5 秒旋转一次屏幕,它永远不会显示任何内容,因为计算大约需要 12秒)。另外,如果我点击一个菜谱,启动一个新活动,然后旋转屏幕,然后点击返回到我的菜谱列表活动,加载器将重新开始计算所有内容。

这是应用程序可接受的行为吗?如何防止这些重复计算的发生?

我的 onCreate 使用带有这一行的加载器:

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

我的活动以这种方式覆盖加载器回调:

@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);
}

我的 RecipesLoader 是我的活动中的一个静态嵌套类:

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);
    }
}

【问题讨论】:

    标签: android loader screen-orientation


    【解决方案1】:

    首先,请考虑检测用户何时到达列表末尾,然后联系服务器,这样可以降低整体加载成本。

    无论如何,这是可能的解决方案:

    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);
        }
    }
    

    食谱

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

    顺便说一句,你可以看看“The Busy Coder's Guide to Android Development”中的第 19 章,它解释了如何处理轮换变化。

    【讨论】:

    • 这似乎并没有解决加载程序完成计算之前屏幕旋转的情况。在这种情况下,将被保存和恢复的状态将是一个空的食谱列表。
    • 菜谱可以一一下载还是小群下载?然后,您可以在获取配方后立即将其添加到列表中,以便在发生轮换时列表中包含一些。您可以跟踪最后获取的配方是什么,然后继续。
    【解决方案2】:

    在 android Menifest 文件中设置 android:configChanges=orientation 的活动。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多