在MVVM架构下用Jetpack Compose、Retrofit及HiltViewModel实现POST请求遇阻求助
解决Jetpack Compose+MVVM+Retrofit+Hilt的POST数据提交问题
1. 核对Retrofit POST接口定义
确保POST注解、参数注解完全匹配后端接口要求:
- JSON格式提交用
@Body传递序列化数据类,禁止混用表单注解; - 表单提交必须添加
@FormUrlEncoded注解,配合@Field或@FieldMap; - 检查接口路径、请求头(如Content-Type)是否和后端一致。
示例JSON请求接口:
interface ApiService { @POST("users") suspend fun createUser(@Body user: User): Response<User> } @Serializable data class User( val name: String, val email: String )
2. 检查ViewModel中的请求逻辑
通过Hilt注入Repository后,用viewModelScope处理异步请求,必须捕获异常并更新UI状态:
@HiltViewModel class UserViewModel @Inject constructor( private val userRepository: UserRepository ) : ViewModel() { private val _uiState = MutableStateFlow<UiState>(UiState.Idle) val uiState: StateFlow<UiState> = _uiState fun submitUser(user: User) { viewModelScope.launch { _uiState.value = UiState.Loading try { val response = userRepository.createUser(user) _uiState.value = if (response.isSuccessful) { UiState.Success(response.body()) } else { UiState.Error("提交失败:${response.message()}") } } catch (e: Exception) { _uiState.value = UiState.Error("网络异常:${e.message}") } } } sealed class UiState { object Idle : UiState() object Loading : UiState() data class Success(val user: User?) : UiState() data class Error(val message: String) : UiState() } }
3. 确认序列化与Retrofit配置
- 必须添加kotlinx-serialization依赖,数据类要加
@Serializable注解; - Retrofit构建时指定JSON转换器,同时添加日志拦截器排查请求细节:
@Module @InstallIn(SingletonComponent::class) object NetworkModule { @Provides fun provideOkHttpClient(): OkHttpClient { return OkHttpClient.Builder() .addInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY // 打印完整请求响应 }) .build() } @Provides fun provideApiService(client: OkHttpClient): ApiService { return Retrofit.Builder() .baseUrl("https://your-api-domain.com/") .client(client) .addConverterFactory(Json.asConverterFactory("application/json".toMediaType())) .build() .create(ApiService::class.java) } }
4. UI层状态收集与提交处理
在Compose中收集ViewModel状态,根据状态更新UI,同时避免重复提交:
@Composable fun UserSubmitScreen(viewModel: UserViewModel = hiltViewModel()) { val uiState by viewModel.uiState.collectAsState() var name by remember { mutableStateOf("") } var email by remember { mutableStateOf("") } Column( modifier = Modifier.fillMaxSize().padding(16.dp), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { OutlinedTextField(value = name, onValueChange = { name = it }, label = { Text("姓名") }) OutlinedTextField(value = email, onValueChange = { email = it }, label = { Text("邮箱") }) Button( onClick = { if (name.isNotEmpty() && email.isNotEmpty()) { viewModel.submitUser(User(name, email)) } }, enabled = uiState !is UserViewModel.UiState.Loading // 加载时禁用按钮 ) { Text(if (uiState is UserViewModel.UiState.Loading) "提交中..." else "提交") } when (uiState) { is UserViewModel.UiState.Success -> Text("提交成功!", color = Color.Green) is UserViewModel.UiState.Error -> Text((uiState as UserViewModel.UiState.Error).message, color = Color.Red) else -> {} } } }
常见排查点
- 查看日志拦截器输出的请求体、响应码,确认参数是否正确发送;
- 检查后端是否接收正确的Content-Type;
- 确保AndroidManifest中添加了网络权限:
<uses-permission android:name="android.permission.INTERNET"/>; - 排查是否存在网络代理、SSL证书问题导致请求无法到达后端。
内容的提问来源于stack exchange,提问作者Ramakrishna
相关产品推荐
相关产品推荐

