本项目实现了一个现代化的 Android 网络请求框架,基于 Retrofit2 + OkHttp + Moshi + Coroutines 构建,提供了完整的网络请求解决方案。
ApiResult封装了所有网络请求的状态(Success、Error、Exception、Loading)- 提供丰富的扩展函数,方便状态判断和数据获取
- 类型安全的响应处理
ApiResponse<T>用于我方标准格式的接口- 支持第三方 API 的原始数据返回
- 自动转换响应格式为
ApiResult
NetworkErrorInterceptor自动处理常见的 HTTP 错误- 统一的错误码映射和异常处理
- 支持自定义网络异常类型
- 支持多种 Retrofit 实例配置
- 可配置的 OkHttp 客户端
- 支持日志拦截器和自定义拦截器
app/src/main/java/com/thisfeng/composestudykit/
├── network/ # 网络框架核心
│ ├── ApiResult.kt # 统一结果包装类
│ ├── ApiResponse.kt # 标准响应格式
│ ├── BaseRepository.kt # Repository 基类
│ ├── NetworkErrorInterceptor.kt # 错误拦截器
│ └── RetrofitClient.kt # Retrofit 客户端工厂
├── data/
│ ├── model/ # 数据模型
│ │ └── Article.kt # 示例数据模型
│ └── api/ # API 接口定义
│ └── WanAndroidApiService.kt # 示例 API 接口
├── ui/
│ ├── screen/ # 界面层
│ │ └── SimpleHomeScreen.kt # 演示界面
│ └── viewmodel/ # ViewModel 层
│ └── SimpleHomeViewModel.kt # 演示 ViewModel
└── MainActivity.kt # 主 Activity
@JsonClass(generateAdapter = true)
data class Article(
val id: Int,
val title: String,
val author: String
// ... 其他字段
)interface WanAndroidApiService {
// 标准格式 API(返回 ApiResponse)
@GET("article/list/{page}/json")
suspend fun getArticles(@Path("page") page: Int): ApiResponse<ArticleList>
// 第三方 API(直接返回原始数据)
@GET("users/{user}/repos")
suspend fun getUserRepos(@Path("user") user: String): List<Repository>
}class ArticleRepository : BaseRepository() {
private val apiService = RetrofitClient.createStandardRetrofit()
.create(WanAndroidApiService::class.java)
// 标准格式 API
suspend fun getArticles(page: Int): ApiResult<ArticleList> {
return safeApiCall { apiService.getArticles(page) }
}
// 第三方 API
suspend fun getUserRepos(user: String): ApiResult<List<Repository>> {
return safeRawApiCall { apiService.getUserRepos(user) }
}
// 组合多个请求
suspend fun getHomeData(): ApiResult<HomeData> {
return try {
val bannerResult = getBanners()
val articlesResult = getArticles(0)
if (bannerResult.isSuccess && articlesResult.isSuccess) {
val homeData = HomeData(
banners = bannerResult.getOrNull() ?: emptyList(),
articles = articlesResult.getOrNull()?.datas ?: emptyList()
)
ApiResult.Success(homeData, "数据加载成功")
} else {
// 返回第一个错误
when {
bannerResult.isError || bannerResult.isException -> bannerResult as ApiResult<HomeData>
else -> articlesResult as ApiResult<HomeData>
}
}
} catch (e: Exception) {
ApiResult.Exception(e)
}
}
}class HomeViewModel : ViewModel() {
private val repository = ArticleRepository()
private val _articles = MutableStateFlow<ApiResult<List<Article>>>(ApiResult.Loading)
val articles: StateFlow<ApiResult<List<Article>>> = _articles.asStateFlow()
fun loadArticles() {
viewModelScope.launch {
_articles.value = ApiResult.Loading
val result = repository.getArticles(0)
_articles.value = result.map { it.datas }
}
}
}@Composable
fun HomeScreen(viewModel: HomeViewModel = viewModel()) {
val articles by viewModel.articles.collectAsState()
when (articles) {
is ApiResult.Loading -> {
CircularProgressIndicator()
}
is ApiResult.Success -> {
val successArticles = articles as ApiResult.Success<List<Article>>
LazyColumn {
items(successArticles.data) { article ->
ArticleItem(article = article)
}
}
}
is ApiResult.Error -> {
val errorArticles = articles as ApiResult.Error
ErrorMessage(
message = errorArticles.message,
onRetry = { viewModel.loadArticles() }
)
}
is ApiResult.Exception -> {
val exceptionArticles = articles as ApiResult.Exception
ErrorMessage(
message = exceptionArticles.exception.message ?: "Unknown error",
onRetry = { viewModel.loadArticles() }
)
}
}
}val customRetrofit = RetrofitClient.createCustomRetrofit(
baseUrl = "https://your-api.com/",
moshi = RetrofitClient.createMoshi(),
okHttpClient = customOkHttpClient
)class AuthInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer your_token")
.build()
return chain.proceed(request)
}
}
// 在创建 OkHttpClient 时添加
val client = RetrofitClient.createDefaultOkHttpClient().newBuilder()
.addInterceptor(AuthInterceptor())
.build()// 我方标准格式
{
"errorCode": 0,
"errorMsg": "成功",
"data": { ... }
}
// 第三方格式(直接返回数据)
{ "key": "value", ... }当前项目包含了一个完整的演示,展示框架的各种功能:
- 模拟网络请求:展示 Loading、Success、Error 状态
- 错误处理:演示网络错误、业务错误的统一处理
- UI 状态管理:完整的状态流转和界面更新
- 协程支持:异步网络请求的现代化处理
- 打开项目并运行
- 点击界面上的按钮测试不同功能
- 观察不同状态下的界面表现
- 始终处理所有
ApiResult状态 - 为用户提供友好的错误提示
- 实现合适的重试机制
- 使用
StateFlow管理异步状态 - 在网络请求时显示加载指示器
- 合理处理状态转换
- 根据业务需求实现缓存策略
- 合理配置网络超时时间
- 使用协程避免阻塞主线程
- Repository 负责数据获取和缓存
- ViewModel 负责业务逻辑和状态管理
- UI 层只负责状态展示和用户交互
- Retrofit2: HTTP 客户端
- OkHttp: 网络请求引擎
- Moshi: JSON 序列化/反序列化
- Kotlin Coroutines: 异步编程
- Jetpack Compose: 现代化 UI
- ViewModel & StateFlow: 状态管理
- 集成 Hilt 依赖注入(可选)
- 添加网络缓存策略
- 支持文件上传/下载
- 添加请求重试机制
- 集成网络状态监听
- 添加更多示例和测试用例
注意: 当前版本专注于核心功能的演示,生产环境使用时建议根据具体需求进行相应的安全配置和性能优化。