Android ViewModel 与没有 Context 的 View 的关系

问题描述 投票:0回答:1

我很难理解如何迁移到 Google 批准的 Android 现代开发。在 MVVM 中,“业务逻辑”应该位于 ViewModel 中,并且建议 ViewModel 的子类应该不感知 Context,但大多数 Android 类需要 Context 才能提供任何功能。例如,如果没有上下文(如 WifiManager 和 ConnectivityManager),就无法获取对系统服务的引用。

作为示例,我正在尝试为具有单个按钮的应用程序构建一个简单的架构,该按钮根据 ConnectivityManager 文档中概述的活动默认网络链接更改其图像。这个系统级操作应该在代码的“业务逻辑”区域中处理,因为它与 UI 无关。它检测网络状态,更改 ViewModel 中的一些状态数据,这应该“神奇地”更改按钮图像,因为某些 Observable 通知 UI 数据已更改并触发 Compose“重组”,从而更改按钮图像。我已经开始构建这个应用程序,我将发布到目前为止我所拥有的内容。如果 ViewModel 是应用程序状态的仲裁者,如何在没有 Context 的情况下创建 ViewModel?这看起来很矛盾。 ViewModel 摘录:

enum class ConnectivityState { WIFI, CELLULAR, DISCONNECTED } class MainActivityViewModel(context: Context) : ViewModel() { private val logger: Logger = LoggerFactory.getLogger(this::class.java) private val _uiState = MutableStateFlow(MainUIState()) val uiState: StateFlow<MainUIState> = _uiState.asStateFlow() //TODO: how to perform system level business logic in ViewModel without Context reference? //DESIRED: keep this 'business logic' away from UI. ViewModel should be appropriate but Context should not be used here? private val wifiManager = context.getSystemService(WIFI_SERVICE) as WifiManager private val connectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager /** * a NetworkCallback which will be triggered when a change in network state is sent from the system */ private val networkCallback = object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { super.onAvailable(network) _uiState.value.connectivityState = getConnectivityState() } override fun onCapabilitiesChanged( network: Network, networkCapabilities: NetworkCapabilities ) { super.onCapabilitiesChanged(network, networkCapabilities) _uiState.value.connectivityState = getConnectivityState() } override fun onLost(network: Network) { super.onLost(network) _uiState.value.connectivityState = getConnectivityState() } } init { connectivityManager.registerDefaultNetworkCallback(networkCallback) _uiState.value.connectivityState = getConnectivityState() } fun getConnectivityState(): ConnectivityState { //these objects represent information about the currently active network val currentNetwork = connectivityManager.getActiveNetwork() val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork) val linkProperties = connectivityManager.getLinkProperties(currentNetwork) if(currentNetwork == null) { return ConnectivityState.DISCONNECTED } if(wifiManager.isWifiEnabled) { //if wifi is enabled, it should be the current active network val isWifi = capabilities?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) if(isWifi != null) { if(isWifi) { //the current active link is a WiFi connection logger.debug("Current active default network is WiFi.") return ConnectivityState.WIFI } } } val isCellular = capabilities?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) if(isCellular != null) { if(isCellular) { logger.info("Current active default network is cellular data.") return ConnectivityState.CELLULAR } } return ConnectivityState.DISCONNECTED } } data class MainUIState( var connectivityState: ConnectivityState = ConnectivityState.DISCONNECTED )

活动摘录:

@Composable fun wifiComposable() { //WiFi button Button( onClick = { MainActivity.openWifiSettings(LocalContext.current) } ) { //TODO: this image changes between DOWN, CELLULAR, WIFI images depending on connectivity state / source Image( //TODO: 'StateFlow.value should not be called within composition' why? //DESIRED BEHAVIOR: when this state value changes, recomp and change image accordingly painter = when(viewModel.uiState.value.connectivityState) { ConnectivityState.WIFI -> painterResource(id = R.drawable.wifi_indicator) ConnectivityState.CELLULAR -> painterResource(id = R.drawable.cellular_indicator) ConnectivityState.DISCONNECTED -> painterResource(id = R.drawable.down_indicator) }, modifier = Modifier.size(40.dp), contentDescription = "WiFi Settings") } }


android kotlin mvvm android-jetpack-compose viewmodel
1个回答
0
投票

演示 - UI 层

在屏幕上显示应用程序数据的UI层。

UI的作用是在屏幕上显示应用数据 也作为用户交互的主要点。每当 数据发生变化,或者由于用户交互(例如按 按钮)或外部输入(如网络响应),UI 应该 更新以反映这些更改。实际上,UI 是一种视觉效果 从数据中检索到的应用程序状态的表示 层。

ViewModel 被视为状态持有者。

数据层

数据层包含应用程序的业务逻辑并公开应用程序数据。

根据您的情况,将网络状态设置为数据源。我建议使用 Dagger Hilt 注入 Context。这毕竟是业务逻辑。对数据执行操作。

© www.soinside.com 2019 - 2024. All rights reserved.