Android中使用ViewModel实现数据仅加载一次的问题咨询
问题根因
使用Navigation Graph跳转页面时,默认会销毁返回栈中前一个Fragment的视图(执行onDestroyView生命周期),返回时会重建视图(执行onCreateView -> onViewCreated)。如果数据加载逻辑写在视图相关的生命周期回调中,每次返回都会触发重复加载。
可行方案
方案1:将数据加载逻辑放到 onCreate 生命周期
onCreate 仅在Fragment实例第一次创建时触发,视图销毁重建不会回调该方法,适合简单场景使用:
class MainFragment : Fragment() { private var loadedData: List<Any>? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 仅首次创建Fragment时加载数据 if (loadedData == null) { // 执行数据加载逻辑 loadData() } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 仅做视图绑定,不触发数据请求 loadedData?.let { bindDataToView(it) } } }
方案2:ViewModel 配合缓存标记(推荐)
ViewModel 生命周期和Fragment实例绑定,长于Fragment视图生命周期,符合MVVM架构规范,同时可以避免配置变更(如屏幕旋转)导致的重复加载:
- 在ViewModel中添加缓存标记与数据缓存
class MainViewModel : ViewModel() { private val _data = MutableLiveData<List<Any>>() val data: LiveData<List<Any>> = _data private var hasLoaded = false fun fetchData() { if (hasLoaded) return viewModelScope.launch { // 执行网络/数据库请求 val result = api.requestMainPageData() _data.postValue(result) hasLoaded = true } } }
- 在Fragment的
onViewCreated中观察数据,直接调用fetchData即可,内部会自动判断是否需要重新请求
方案3:升级Navigation版本开启默认视图保存
Navigation 2.4.0及以上版本默认支持多返回栈视图保存,不会销毁返回栈中Fragment的视图,返回时直接恢复现有视图,无需修改业务逻辑:
只需将项目中Navigation相关依赖的版本升级到2.4.0或更高即可。
方案4:自定义标记位判断
在Fragment中添加布尔标记位,首次加载成功后标记为已加载,后续加载前先判断标记:
class MainFragment : Fragment() { private var isDataLoaded = false override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) if (!isDataLoaded) { loadData() isDataLoaded = true } } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) // 保存标记位,避免配置变更后丢失 outState.putBoolean("is_loaded", isDataLoaded) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 恢复标记位 isDataLoaded = savedInstanceState?.getBoolean("is_loaded") ?: false } }
注意事项
- 如果业务需要每次返回页面都刷新数据,不要开启上述缓存逻辑,可搭配下拉刷新组件实现手动刷新
- 长期缓存数据需要添加缓存更新机制,避免用户长时间看到过期数据
内容的提问来源于stack exchange,提问作者user1354033
相关产品推荐
相关产品推荐

