核心概念:POST 请求
在开始编码前,我们先简单理解一下 POST 请求:

- 用途:用于向服务器提交数据,通常用于创建新资源(如注册用户、发布文章)或更新已有资源。
- 数据位置:数据可以放在请求体中,而不是像 GET 请求那样放在 URL 里,这使得 POST 可以发送大量数据,并且数据对用户是不可见的。
- 安全性:相比 GET,POST 更安全,因为它不会将敏感数据暴露在 URL 或服务器日志中(但数据本身仍然需要加密,如使用 HTTPS)。
现代推荐 - 使用 Retrofit + OkHttp (业界标准)
对于任何新项目,强烈推荐使用 Retrofit,它是一个类型安全的 HTTP 客户端,由 Square 公司(就是那个做 ButterKnife 的公司)开发,它将网络请求简化为简单的 Java/Kotlin 接口调用,非常优雅和高效。
Retrofit 内部默认使用 OkHttp 来处理底层的网络连接。
添加依赖
在你的 app/build.gradle.kts (或 build.gradle) 文件中添加依赖:
// build.gradle.kts (Kotlin DSL)
dependencies {
// Retrofit: 用于定义和执行 API 接口
implementation("com.squareup.retrofit2:retrofit:2.9.0")
// Gson: 用于 JSON 数据的序列化与反序列化
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
// OkHttp: 网络请求的底层实现
implementation("com.squareup.okhttp3:okhttp:4.11.0")
// Coroutines: 用于异步处理,推荐与 Retrofit 配合使用
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
}
添加网络权限
在 app/src/main/AndroidManifest.xml 中添加网络权限:

<manifest ...>
<uses-permission android:name="android.permission.INTERNET" />
<application ...>
...
</application>
</manifest>
创建数据模型
创建一个 Kotlin 数据类来映射服务器返回的 JSON 数据。
// User.kt
data class User(
val id: Int,
val name: String,
val email: String
)
// API 响应的通用结构(如果服务器返回的是这种格式)
data class ApiResponse<T>(
val code: Int,
val message: String,
val data: T
)
定义 API 接口
创建一个接口,用注解来描述你的 API 端点。
// ApiService.kt
import retrofit2.Call
import retrofit2.http.*
interface ApiService {
// 发送 JSON 数据
@POST("api/users")
suspend fun createUser(
@Body user: User // @Body 注解表示将 user 对象作为 JSON 放入请求体
): User // suspend 关键字使其可以在协程中直接调用,无需手动处理 Call
// 发送表单数据 (application/x-www-form-urlencoded)
@POST("api/login")
suspend fun login(
@Field("username") username: String,
@Field("password") password: String
): User
// 发送键值对 (multipart/form-data),适合上传文件
@Multipart
@POST("api/upload")
suspend fun uploadFile(
@Part("file") file: okhttp3.MultipartBody.Part,
@Part("description") description: RequestBody
): String
}
创建 Retrofit 实例并调用
// ApiClient.kt
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object ApiClient {
private const val BASE_URL = "https://your-api-server.com/" // 替换为你的服务器地址
val instance: ApiService by lazy {
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
retrofit.create(ApiService::class.java)
}
}
在 Activity/ViewModel 中使用 (协程方式)
这是最推荐的异步调用方式,代码简洁且易于管理。
// MainActivity.kt
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import kotlinx.coroutines.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val btnPost = findViewById<Button>(R.id.btn_post)
btnPost.setOnClickListener {
// 在协程作用域中执行网络请求
CoroutineScope(Dispatchers.IO).launch {
try {
// 1. 准备数据
val newUser = User(name = "John Doe", email = "john.doe@example.com")
// 2. 调用 API
val response = ApiClient.instance.createUser(newUser)
// 3. 切换到主线程更新 UI
withContext(Dispatchers.Main) {
Toast.makeText(this@MainActivity, "创建用户成功: ${response.name}", Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
// 4. 处理错误
withContext(Dispatchers.Main) {
Toast.makeText(this@MainActivity, "请求失败: ${e.message}", Toast.LENGTH_SHORT).show()
}
}
}
}
}
}
传统方式 - 使用 OkHttp 直接发送请求
如果你不想引入 Retrofit,或者只是想做一个简单的请求,可以直接使用 OkHttp。

添加依赖
同上,需要 okhttp 和 okhttp-tls (如果需要 HTTPS)。
发送 POST 请求示例
import okhttp3.*
import java.io.IOException
// 创建 OkHttp 客户端
val client = OkHttpClient()
// 准备请求体 (JSON 格式)
val mediaType = MediaType.Companion.parse("application/json; charset=utf-8")
val jsonBody = """{"name": "Jane Doe", "email": "jane.doe@example.com"}"""
val body = RequestBody.Companion.create(mediaType, jsonBody)
// 构建请求
val request = Request.Builder()
.url("https://your-api-server.com/api/users") // 替换为你的 URL
.post(body) // 指定 POST 请求并设置请求体
.build()
// 发送请求 (同步方式,会阻塞线程,不推荐在主线程使用)
try {
val response = client.newCall(request).execute()
if (response.isSuccessful) {
val responseBody = response.body?.string()
println("响应成功: $responseBody")
} else {
println("请求失败: ${response.code}")
}
} catch (e: IOException) {
e.printStackTrace()
}
// 发送请求 (异步方式,推荐)
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
// 请求失败
e.printStackTrace()
}
override fun onResponse(call: Call, response: Response) {
// 请求成功
if (response.isSuccessful) {
val responseBody = response.body?.string()
// 注意:这里不能直接更新 UI,需要切换到主线程
println("响应成功: $responseBody")
} else {
println("请求失败: ${response.code}")
}
}
})
最佳实践与注意事项
-
永远不要在主线程执行网络请求 Android 的主线程(UI 线程)负责处理用户界面交互,如果在主线程进行网络请求,会导致应用无响应(ANR - Application Not Responding)。
- 解决方案:使用
Thread+Handler、AsyncTask(已废弃)、ExecutorService,或者更现代的 Kotlin Coroutines 或 RxJava,Retrofit + Coroutines 是目前最优雅的组合。
- 解决方案:使用
-
处理网络状态 在发送请求前,最好检查一下网络是否可用。
fun isNetworkAvailable(context: Context): Boolean { val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val activeNetwork = connectivityManager.activeNetwork val caps = connectivityManager.getNetworkCapabilities(activeNetwork) return caps != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) } else { // 对于旧版本 API val networkInfo = connectivityManager.activeNetworkInfo return networkInfo != null && networkInfo.isConnected } } -
安全性:使用 HTTPS 在生产环境中,必须使用 HTTPS 协议来加密数据传输,防止中间人攻击和数据泄露,OkHttp 和 Retrofit 都默认支持 HTTPS。
-
错误处理 网络请求可能因为各种原因失败:无网络、服务器宕机、服务器返回 4xx/5xx 错误、JSON 解析失败等,代码中必须有完善的错误处理机制。
-
数据序列化
- JSON:推荐使用 Moshi 或 Gson,Moshi 是 Square 公司推出的,性能更好,并且对 Kotlin 支持更友好。
- Protobuf:如果对性能要求极高,可以使用 Protocol Buffers。
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Retrofit + OkHttp | 类型安全、代码简洁、功能强大(支持协程/RxJava)、可扩展性好、社区活跃 | 引入了第三方库,有一定学习成本 | 所有新项目,尤其是复杂应用 |
| OkHttp 直接请求 | 轻量级,无需额外抽象,适合简单、一次性的请求 | 代码冗余,手动处理线程、JSON 转换等,不易维护 | 简单工具、快速原型、学习网络基础 |
对于绝大多数 Android 学习和使用 Retrofit 是必不可少的技能,它能让你从繁琐的网络细节中解放出来,专注于业务逻辑。
