
当设备切换 wi-fi 网络时,recyclerview 显示的数据意外清空,重启 app 后数据恢复——这通常源于未妥善处理网络状态变化导致的缓存失效或数据源重置,需结合生命周期管理、本地缓存与网络监听实现鲁棒性恢复。
当设备切换 wi-fi 网络时,recyclerview 显示的数据意外清空,重启 app 后数据恢复——这通常源于未妥善处理网络状态变化导致的缓存失效或数据源重置,需结合生命周期管理、本地缓存与网络监听实现鲁棒性恢复。
在 Android 开发中,RecyclerView 本身不持有数据,其显示内容完全依赖于 Adapter 绑定的 List
根本原因并非 RecyclerView 或 Adapter 本身缺陷,而是数据生命周期与网络状态解耦:应用未监听网络变化,也未在连接恢复后主动刷新数据;同时缺乏离线缓存机制,导致网络中断期间无法回退到已加载数据。
✅ 正确实践:三步构建网络韧性 UI
1. 监听网络状态变化(推荐使用 ConnectivityManager.NetworkCallback,兼容 Android 7.0+)
BroadcastReceiver 方式(如 CONNECTIVITY_ACTION)已自 Android 7.0 起受限,建议改用更精准、无权限要求的 NetworkCallback:
private ConnectivityManager.NetworkCallback networkCallback;
private void registerNetworkCallback(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
networkCallback = new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(@NonNull Network network) {
Log.d("Network", "Connected");
refreshDataIfNecessary(); // 如需自动刷新,此处调用数据加载逻辑
}
@Override
public void onLost(@NonNull Network network) {
Log.d("Network", "Disconnected");
// 可选:Toast 提示“网络已断开”,但不清空现有数据
showOfflineHint();
}
};
cm.registerDefaultNetworkCallback(networkCallback);
}
private void unregisterNetworkCallback(Context context) {
if (networkCallback != null) {
((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE))
.unregisterNetworkCallback(networkCallback);
}
}
⚠️ 注意:务必在 Activity.onDestroy() 或 Fragment.onDestroyView() 中调用 unregisterNetworkCallback(),避免内存泄漏。
Android开发教程与笔记pdf版下载Android文件存取与数据库编程知识,文件操作主要是读文件、写文件、读取静态文件等,同时还介绍了创建添加文件内容并保存,打开文件并显示内容;数据库编程方面主要介绍了SQLite数据库的使用、包括创建、删除、打开数据库、非查询SQL操作指令、查询SQL指令-游标Cursors等知识。
2. 数据层增强:引入本地缓存 + 状态感知
不要将 List
// 在 ViewModel 中
private final MutableLiveData<list>> mesaList = new MutableLiveData();
private final MutableLiveData<boolean> isLoading = new MutableLiveData();
public LiveData<list>> getMesaList() { return mesaList; }
public LiveData<boolean> getIsLoading() { return isLoading; }
public void loadMesas() {
isLoading.setValue(true);
// ① 优先读取本地数据库(Room)缓存
localDb.mesaDao().getAll().observeForever(list -> {
mesaList.setValue(list); // 即使网络失败,也展示缓存
isLoading.setValue(false);
});
// ② 同时尝试网络拉取(成功后更新本地库 + 刷新 UI)
apiService.getMesas().enqueue(new Callback<list>>() {
@Override
public void onResponse(Call<list>> call, Response<list>> response) {
if (response.isSuccessful()) {
localDb.mesaDao().insertAll(response.body());
mesaList.setValue(response.body()); // 主动通知刷新
}
isLoading.setValue(false);
}
@Override
public void onFailure(Call<list>> call, Throwable t) {
isLoading.setValue(false); // 失败时不覆盖已有缓存
}
});
}</list></list></list></list></boolean></list></boolean></list>
3. Adapter 改造:支持空状态与加载态(提升用户体验)
在 MesaAdapter 中添加状态标识,配合 DiffUtil 避免全量刷新:
public class MesaAdapter extends RecyclerView.Adapter<mesaviewholder> {
private List<mesa> mesas = Collections.emptyList();
private boolean isOffline = false;
public void submitList(List<mesa> newList, boolean offlineMode) {
this.mesas = newList != null ? newList : Collections.emptyList();
this.isOffline = offlineMode;
notifyDataSetChanged();
}
@Override
public void onBindViewHolder(@NonNull MesaViewHolder holder, int position) {
if (position <p>并在 UI 层观察数据状态:</p>
<pre class="brush:php;toolbar:false;">viewModel.getMesaList().observe(this, mesas -> {
adapter.submitList(mesas, !viewModel.isNetworkAvailable());
recyclerView.setVisibility(mesas.isEmpty() ? View.GONE : View.VISIBLE);
emptyView.setVisibility(mesas.isEmpty() ? View.VISIBLE : View.GONE);
});
✅ 总结
- ❌ 错误做法:仅靠 WeakReference
和裸 List 传递数据,忽视数据持久性与生命周期; - ✅ 正确路径:
→ 使用 NetworkCallback 替代过时广播;
→ 将数据托管至 ViewModel + Room 缓存,实现「有网同步、无网展示」;
→ Adapter 仅负责渲染,不承担数据获取与生存期管理;
→ 所有网络变更响应必须配套 UI 状态反馈(如加载中、离线提示、空状态)。
如此设计,不仅能解决 Wi-Fi 切换导致的数据丢失,更能显著提升应用离线可用性与用户信任感。











