Android Compose 无网络状态处理全指南:从基础到高级实践

Android Compose 无网络状态界面处理全方案

引言

在移动应用开发中,网络连接不稳定是常见场景。优雅地处理无网络状态能显著提升用户体验。Jetpack Compose 提供了强大的工具来实现各种网络状态下的界面展示。本文将全面介绍在 Compose 中处理无网络状态的多种方案。

一、基础网络状态检测

1. 网络状态检测工具类

class NetworkMonitor(private val context: Context) {
    val isOnline: Boolean
        get() {
            val connectivityManager = 
                context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val networkCapabilities = 
                connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
            
            return networkCapabilities?.let {
                it.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
                it.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
                it.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)
            } ?: false
        }
}

2. 网络状态 ViewModel

class NetworkViewModel(private val networkMonitor: NetworkMonitor) : ViewModel() {
    private val _isOnline = mutableStateOf(networkMonitor.isOnline)
    val isOnline: State<Boolean> = _isOnline

    fun checkNetworkStatus() {
        _isOnline.value = networkMonitor.isOnline
    }
}

二、简单界面处理方案

1. 全屏覆盖式

@Composable
fun SimpleScreen() {
    val isOnline by networkViewModel.isOnline.collectAsState()
    
    Box(modifier = Modifier.fillMaxSize()) {
        // 主内容
        MainContent()
        
        // 无网络覆盖层
        if (!isOnline) {
            Surface(
                color = MaterialTheme.colors.background.copy(alpha = 0.9f),
                modifier = Modifier.fillMaxSize()
            ) {
                OfflineContent()
            }
        }
    }
}

@Composable
fun OfflineContent() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Icon(Icons.Filled.WifiOff, contentDescription = null, modifier = Modifier.size(64.dp))
        Spacer(Modifier.height(16.dp))
        Text("无网络连接", style = MaterialTheme.typography.h5)
        Text("请检查您的网络设置", style = MaterialTheme.typography.body1)
        Spacer(Modifier.height(24.dp))
        Button(onClick = { /* 重试 */ }) {
            Text("重试连接")
        }
    }
}

三、复杂界面处理方案

1. 局部替换法

@Composable
fun ComplexScreen() {
    val isOnline by networkViewModel.isOnline.collectAsState()
    
    Scaffold(
        topBar = { AppBar() },
        bottomBar = { BottomBar() }
    ) { padding ->
        Column(modifier = Modifier.padding(padding)) {
            // 不依赖网络的部分
            LocalFeatures()
            
            // 依赖网络的部分
            if (isOnline) {
                OnlineContent()
            } else {
                NetworkErrorCard(
                    title = "网络内容",
                    message = "此部分需要网络连接",
                    onRetry = { /* 重试 */ }
                )
            }
            
            // 更多内容...
        }
    }
}

2. 分区块处理

@Composable
fun DashboardScreen() {
    val networkState by rememberNetworkState()
    
    LazyColumn {
        item { HeaderSection() }
        
        item { 
            if (networkState.isOnline) {
                LiveDataSection()
            } else {
                OfflinePlaceholder(
                    icon = Icons.Filled.Update,
                    title = "实时数据"
                )
            }
        }
        
        item { 
            if (networkState.isOnline) {
                RecommendationsSection()
            } else {
                OfflinePlaceholder(
                    icon = Icons.Filled.Star,
                    title = "个性化推荐"
                )
            }
        }
    }
}

3. 渐进式显示

@Composable
fun NewsFeedScreen(viewModel: NewsViewModel = viewModel()) {
    val uiState by viewModel.uiState.collectAsState()
    
    when {
        uiState.isLoading -> FullScreenLoading()
        !uiState.isOnline && uiState.cachedItems.isEmpty() -> FullScreenError()
        !uiState.isOnline -> {
            Column {
                CachedNewsList(uiState.cachedItems)
                OfflineBanner()
            }
        }
        else -> NewsList(uiState.items)
    }
}

四、高级网络状态管理

1. 增强版网络状态管理器

class AdvancedNetworkMonitor(context: Context) {
    sealed class NetworkState {
        object Available : NetworkState()
        object Unavailable : NetworkState()
        data class Limited(val type: ConnectionType) : NetworkState()
    }
    
    enum class ConnectionType { WIFI, CELLULAR, ETHERNET, VPN, OTHER }
    
    private val _state = mutableStateOf<NetworkState>(NetworkState.Available)
    val state: State<NetworkState> = _state
    
    init {
        val cm = context.getSystemService(ConnectivityManager::class.java)
        val request = NetworkRequest.Builder()
            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            .build()
        
        cm.registerNetworkCallback(request, object : ConnectivityManager.NetworkCallback() {
            override fun onAvailable(network: Network) {
                _state.value = NetworkState.Available
            }
            
            override fun onLost(network: Network) {
                _state.value = NetworkState.Unavailable
            }
            
            override fun onCapabilitiesChanged(
                network: Network,
                capabilities: NetworkCapabilities
            ) {
                _state.value = when {
                    capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> 
                        NetworkState.Limited(ConnectionType.WIFI)
                    capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> 
                        NetworkState.Limited(ConnectionType.CELLULAR)
                    capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> 
                        NetworkState.Limited(ConnectionType.VPN)
                    else -> NetworkState.Available
                }
            }
        })
    }
}

2. 状态监听Composable

@Composable
fun rememberNetworkState(): State<NetworkState> {
    val context = LocalContext.current
    val networkMonitor = remember { AdvancedNetworkMonitor(context) }
    
    return networkMonitor.state
}

五、UI组件库

1. 离线占位符组件

@Composable
fun OfflinePlaceholder(
    title: String,
    message: String = "需要网络连接",
    icon: ImageVector = Icons.Filled.CloudOff,
    onRetry: (() -> Unit)? = null
) {
    Card(
        elevation = 4.dp,
        modifier = Modifier
            .fillMaxWidth()
            .padding(8.dp)
    ) {
        Column(
            modifier = Modifier.padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Icon(
                imageVector = icon,
                contentDescription = null,
                tint = MaterialTheme.colors.error,
                modifier = Modifier.size(48.dp)
            )
            Spacer(Modifier.height(8.dp))
            Text(title, style = MaterialTheme.typography.h6)
            Text(message, style = MaterialTheme.typography.body2)
            
            onRetry?.let {
                Spacer(Modifier.height(16.dp))
                Button(onClick = it) {
                    Text("重试")
                }
            }
        }
    }
}

2. 顶部横幅通知

@Composable
fun NetworkStatusBanner() {
    val networkState by rememberNetworkState()
    val showBanner = networkState is NetworkState.Unavailable
    
    AnimatedVisibility(
        visible = showBanner,
        enter = slideInVertically { -it },
        exit = slideOutVertically { -it }
    ) {
        Surface(
            color = MaterialTheme.colors.error,
            modifier = Modifier.fillMaxWidth()
        ) {
            Row(
                modifier = Modifier.padding(8.dp),
                verticalAlignment = Alignment.CenterVertically
            ) {
                Icon(Icons.Filled.WifiOff, "离线", tint = MaterialTheme.colors.onError)
                Spacer(Modifier.width(8.dp))
                Text("离线模式 - 部分功能不可用", color = MaterialTheme.colors.onError)
            }
        }
    }
}

六、最佳实践建议

  1. 分层处理:根据界面复杂度选择全屏覆盖或局部替换
  2. 缓存策略:尽可能显示缓存内容并明确标注
  3. 明确反馈:让用户清楚知道当前是离线状态
  4. 恢复途径:提供明显的重试或刷新选项
  5. 状态细分:区分完全离线、弱网等不同状态
  6. 视觉一致:保持离线UI与应用设计风格一致
  7. 性能考虑:避免不必要的网络状态监听和重组

结语

在Compose中处理无网络状态需要综合考虑用户体验、界面复杂度和技术实现。本文介绍的各种方案可以根据实际需求灵活组合使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值