AsyncTaskLoader配置变更处理异常:锁屏/切后台后重复加载数据求助
问题分析与解决方案
首先咱们先拆解下为什么会出现这种差异:
- 设备旋转时,系统会重建Activity,但LoaderManager会自动保留已存在的Loader实例,新创建的Activity会直接关联这个已经加载完数据的Loader,所以只会触发
onLoadFinished(),不会重新走加载流程。 - 而按Home键退到后台、锁屏再解锁时,Activity会经历
onStop()->onStart()的生命周期切换。默认情况下,AsyncTaskLoader在Activity回到前台时会调用onStartLoading(),如果Loader没保留之前的数据,也没加判断逻辑阻止重复加载,就会触发loadInBackground()重新请求API。
下面是针对性的解决办法:
1. 重写onStartLoading(),控制加载触发时机
在你的AsyncTaskLoader子类里,添加判断逻辑:只有数据为空,或者收到内容变化通知时,才启动加载,否则直接交付已有数据:
public class YourDataLoader extends AsyncTaskLoader<List<YourDataModel>> { private List<YourDataModel> mLoadedData; public YourDataLoader(Context context) { super(context); } @Override protected void onStartLoading() { // 如果已有加载完成的数据,直接交给回调,不重复请求 if (mLoadedData != null) { deliverResult(mLoadedData); } // 仅当数据为空,或收到内容变化通知时,强制触发加载 if (takeContentChanged() || mLoadedData == null) { forceLoad(); } } @Override public List<YourDataModel> loadInBackground() { // 这里写你的API请求逻辑 return fetchDataFromApi(); } @Override public void deliverResult(List<YourDataModel> data) { mLoadedData = data; super.deliverResult(data); } }
2. 确保onLoadFinished()逻辑正确
在Activity/Fragment的Loader回调里,只需要专注更新UI即可,数据已经被Loader内部保存了:
@Override public void onLoadFinished(Loader<List<YourDataModel>> loader, List<YourDataModel> data) { // 更新适配器与UI yourAdapter.setData(data); yourAdapter.notifyDataSetChanged(); }
3. 正确初始化Loader
在Activity的onCreate()中,使用initLoader()而非restartLoader()来初始化Loader,这样系统会自动复用已存在的Loader实例:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_activity_layout); // 初始化Loader,参数依次为Loader ID、额外参数、回调接口 getSupportLoaderManager().initLoader(LOADER_ID, null, this); }
原理说明
通过在Loader内部缓存已加载的数据,并重写onStartLoading()添加判断逻辑,我们可以避免Activity每次从后台回到前台都重复请求API。只有首次加载(数据为空),或者你主动调用onContentChanged()触发刷新时,才会重新执行loadInBackground()。
内容的提问来源于stack exchange,提问作者KKrzyzek
相关产品推荐
相关产品推荐

