Android中使用Retrofit2+Hilt如何处理断网场景下的网络错误响应?
离线网络错误处理方案
1. 网络状态前置检查
发起请求前先判断设备联网状态,避免无意义请求触发崩溃:
- 先在
AndroidManifest.xml添加必要权限:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- 封装网络状态检测工具类,可通过Hilt注入到需要调用的位置,无网络时直接返回错误提示,不发起请求。
2. 统一捕获请求异常
离线时Retrofit会抛出IOException,未捕获就会直接崩溃,建议用密封类封装请求结果,在Repository层统一处理异常:
- 定义请求结果密封类:
sealed class Result<out T> { data class Success<out T>(val data: T): Result<T>() data class Error(val errorMsg: String, val exception: Exception? = null): Result<Nothing>() }
- 封装请求逻辑统一捕获异常:
suspend fun getRecipeList(): Result<List<Recipe>> { return try { val response = recipeService.getList() Result.Success(response.data) } catch (e: IOException) { Result.Error("当前无网络,请检查连接后重试", e) } catch (e: Exception) { Result.Error("请求失败,请稍后重试", e) } }
3. UI层适配错误状态
ViewModel把处理好的状态暴露给Compose层,展示对应错误提示即可:
- ViewModel中定义UI状态:
val recipeUiState = MutableStateFlow<RecipeUiState>(RecipeUiState.Loading) sealed class RecipeUiState { object Loading: RecipeUiState() data class Success(val data: List<Recipe>): RecipeUiState() data class Error(val msg: String): RecipeUiState() } fun fetchRecipe() = viewModelScope.launch { recipeUiState.value = RecipeUiState.Loading val result = recipeRepository.getRecipeList() recipeUiState.value = when(result) { is Result.Success -> RecipeUiState.Success(result.data) is Result.Error -> RecipeUiState.Error(result.errorMsg) } }
- Compose层监听状态,错误时展示Toast或者全屏错误提示页即可。
4. 可选:添加离线缓存
如果需要离线也能查看历史数据,可以修改你提供的Retrofit配置,搭配OkHttp缓存实现离线读取:
@Singleton @Provides fun provideRecipeService(@ApplicationContext context: Context) : RecipeService { // 配置100M缓存空间 val cache = Cache(context.cacheDir, 100L * 1024 * 1024) val okHttpClient = OkHttpClient.Builder() .cache(cache) .addInterceptor { chain -> val request = if (isNetworkAvailable(context)) { // 有网时缓存1小时 chain.request().newBuilder() .header("Cache-Control", "public, max-age=3600") .build() } else { // 无网时读取7天内的缓存 chain.request().newBuilder() .header("Cache-Control", "public, only-if-cached, max-stale=604800") .build() } chain.proceed(request) } .build() return Retrofit.Builder() .baseUrl("https://food2fork.ca/api/recipe/") .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build() .create(RecipeService::class.java) }
内容的提问来源于stack exchange,提问作者Jeevan Rupacha
相关产品推荐
相关产品推荐

