MVVM架构下全应用数据共享方案问询(含Hilt、网络状态监听场景)
全应用共享ViewModel关联数据的实现方案
核心原则
首先明确两个错误方案不可取:
- 不要将全局共享状态存在Activity的公共
var中,既没有可观察能力,也有极高的内存泄漏风险,不符合单向数据流规范 - 不要强行将Activity级ViewModel共享给所有子页面,会导致严重的耦合问题,Compose场景下默认不会出现一个页面对应两个ViewModel的问题:
viewModel()默认和当前导航栈条目生命周期绑定,如果你需要获取Activity级ViewModel,只需要传参viewModelStoreOwner = LocalContext.current as ComponentActivity即可,不会生成新的实例
基础实现方案(无DI框架场景)
- 网络状态这类全局通用状态,优先封装成生命周期和应用一致的单例状态持有者,独立于Activity、ViewModel存在
- 如果不想做单例,也可以将网络状态存在Activity级的
MainViewModel的StateFlow/LiveData属性中,子页面ViewModel需要时直接传入该状态对象即可,不需要持有整个MainViewModel实例
进阶方案(Hilt + StateFlow 场景,适配你提供的项目结构)
思路:用Hilt注入一个单例的网络状态监视器,所有需要网络状态的ViewModel都直接注入这个实例订阅状态即可,完全不需要和Activity、其他ViewModel耦合,代码侵入性极低。
第一步:定义单例网络状态监视器
// 网络状态枚举 enum class NetworkState { AVAILABLE, UNAVAILABLE } @Singleton class NetworkMonitor @Inject constructor( @ApplicationContext context: Context ) { private val connectivityManager = context.getSystemService(ConnectivityManager::class.java) private val _networkState = MutableStateFlow(NetworkState.AVAILABLE) val networkState: StateFlow<NetworkState> = _networkState.asStateFlow() private val networkCallback = object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { _networkState.update { NetworkState.AVAILABLE } } override fun onLost(network: Network) { _networkState.update { NetworkState.UNAVAILABLE } } } init { // 初始化时自动注册回调,和应用生命周期绑定,不需要在Activity中注册 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { connectivityManager.registerDefaultNetworkCallback(networkCallback) } else { val request = NetworkRequest.Builder().build() connectivityManager.registerNetworkCallback(request, networkCallback) } } // 可选:应用退出时调用解除注册 fun release() { runCatching { connectivityManager.unregisterNetworkCallback(networkCallback) } } }
第二步:在业务ViewModel中注入使用
比如你的BottomSheetViewModel可以直接组合网络状态和业务请求状态:
@HiltViewModel class BottomSheetViewModel @Inject constructor( networkMonitor: NetworkMonitor, // 其他业务依赖,比如仓库层实例 ) : ViewModel() { // 组合网络状态和业务请求状态 val state: StateFlow<RequestState> = combine( networkMonitor.networkState, // 你的业务请求返回的Flow businessRequestFlow ) { networkState, businessState -> if (networkState == NetworkState.UNAVAILABLE) { RequestState.NO_CONNECTION } else { businessState } }.stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5000), initialValue = RequestState.Loading ) } // 你的业务请求状态枚举示例 enum class RequestState { Loading, Success, Error, NO_CONNECTION }
第三步:简化Activity侧代码
不需要在Activity中处理任何网络状态相关逻辑:
@AndroidEntryPoint class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 不需要在这里注册网络回调、更新ViewModel状态 setContent { NavHost(...) { composable("bottom_sheet") { // 直接获取Hilt注入的ViewModel即可,内部已经自动注入了NetworkMonitor val bottomSheetViewModel = viewModel<BottomSheetViewModel>() BottomSheet( state = bottomSheetViewModel.state.collectAsStateWithLifecycle().value ) } } } } }
额外说明
- 如果需要使用LiveData替换StateFlow,只需要把
NetworkMonitor里的状态容器换成MutableLiveData,ViewModel侧用MediatorLiveData或者Transformations.switchMap组合状态即可,逻辑完全一致 - 该方案下所有ViewModel都可以独立订阅全局网络状态,不需要互相持有、也不需要依赖宿主组件,完全解耦
- 如果你需要共享其他全应用范围的状态,都可以参考这个思路,封装成单例的状态持有者注入使用即可
内容的提问来源于stack exchange,提问作者Lorenzo Benevento
相关产品推荐
相关产品推荐

