目录
- 核心概念:客户端-服务器模型
- 准备工作:服务器端
- Android 客户端发送数据的几种主流方式
- 使用
HttpURLConnection(原生 Java API,无需第三方库) - 使用 OkHttp (强烈推荐,现代 Android 开发标准)
- 使用 Retrofit (高级 REST API 客户端,基于 OkHttp)
- 使用
- 数据格式选择:JSON vs. Form-Data
- 关键注意事项:网络权限、子线程、数据安全
- 完整示例:使用 OkHttp 发送 JSON 数据
- 进阶话题:文件上传、断点续传、进度监听
核心概念:客户端-服务器模型
想象一下你去餐厅点餐:

- 你的手机 (Android Client):是发起请求的一方,它决定要“发送什么数据”(比如点一份宫保鸡丁)。
- 餐厅厨房 (Server):是接收和处理请求的一方,它根据你的订单(数据)来“做菜”(处理业务逻辑)。
- 服务员 (HTTP 协议):是你们之间的沟通方式,你通过服务员(
POST/GET请求)把订单(数据)送到厨房,厨房做完菜后,服务员再把结果(响应)端给你。
在技术上,你的手机会向一个特定的网络地址(URL,即餐厅地址)发送一个 HTTP 请求,这个请求包含了:
- 请求方法:
GET(获取数据,像看菜单)、POST(提交数据,像下订单)、PUT(更新数据)、DELETE(删除数据)等,我们最常用的是POST。 - 请求头:一些附加信息,比如内容类型
Content-Type(告诉服务器我发的是什么格式数据)、认证信息等。 - 请求体:实际要发送的数据内容。
服务器收到请求后,处理数据,然后返回一个 HTTP 响应,包含:
- 响应状态码:
200 OK(成功)、404 Not Found(资源不存在)、500 Internal Server Error(服务器内部错误)等。 - 响应头:服务器返回的附加信息。
- 响应体:服务器返回的数据内容。
准备工作:服务器端
在写 Android 代码之前,你必须有一个可以接收数据的服务器端,这个服务器端可以是:
- 你自己用 Node.js, Python (Django/Flask), Java (Spring Boot), PHP 等语言搭建的。
- 云函数,如阿里云函数计算、腾讯云云函数、AWS Lambda。
- 第三方 Backend-as-a-Service (BaaS) 平台,如 Firebase, LeanCloud。
为了演示,我们假设一个简单的服务器端 API 端点:

- URL:
https://your-api-domain.com/api/users - 方法:
POST - 期望的请求头:
Content-Type: application/json - 期望的请求体 (JSON):
{ "name": "张三", "email": "zhangsan@example.com" } - 成功响应 (JSON):
{ "status": "success", "message": "User created successfully", "user_id": "12345" }
Android 客户端发送数据的几种主流方式
使用 HttpURLConnection (原生 Java API)
这是 Android SDK 自带的 API,无需添加任何依赖,但它的代码比较冗长,且功能相对基础。
优点:
- 无需第三方库,减少应用体积。
- 适用于简单的网络请求。
缺点:
- 代码繁琐,需要手动管理线程、输入输出流。
- 功能不如第三方库强大(如连接池、拦截器)。
示例代码:

// 必须在子线程中执行,或者使用 AsyncTask (已废弃) / Executor
new Thread(new Runnable() {
@Override
public void run() {
String url = "https://your-api-domain.com/api/users";
try {
URL urlObj = new URL(url);
HttpURLConnection connection = (HttpURLConnection) urlObj.openConnection();
// 设置请求方法
connection.setRequestMethod("POST");
// 设置请求头
connection.setRequestProperty("Content-Type", "application/json");
// 允许输出请求体
connection.setDoOutput(true);
// 构建要发送的 JSON 数据
String jsonInputString = "{\"name\":\"张三\",\"email\":\"zhangsan@example.com\"}";
// 写入请求体
try (OutputStream os = connection.getOutputStream()) {
byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
// 获取响应码
int responseCode = connection.getResponseCode();
System.out.println("Response Code: " + responseCode);
// 读取响应
if (responseCode == HttpURLConnection.HTTP_OK) { // success
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
System.out.println("Server Response: " + response.toString());
// 在这里可以处理服务器返回的数据
} else {
System.out.println("POST request failed");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
使用 OkHttp (强烈推荐)
OkHttp 是目前 Android 开发中最流行的网络请求库,它高效、易用,并内置了对 HTTP/2 和 SPDY 的支持。
优点:
- 性能优异,有连接池。
- API 简洁,易于使用。
- 支持异步和同步请求。
- 强大的拦截器机制,可以统一处理日志、认证等。
第一步:添加依赖
在 app/build.gradle 文件的 dependencies 代码块中添加:
dependencies {
implementation("com.squareup.okhttp3:okhttp:4.12.0") // 使用最新版本
}
第二步:添加网络权限
在 app/src/main/AndroidManifest.xml 中添加:
<uses-permission android:name="android.permission.INTERNET" />
如果你的 App 针对 Android 9 (API 28) 或更高版本,默认情况下是明文流量,如果你的 API 是 https,则无需额外配置,如果是 http,需要在 application 标签下添加:
android:usesCleartextTraffic="true"
注意:强烈建议服务器使用 https 协议。
第三步:编写代码
发送同步请求 (在子线程中执行):
// 必须在子线程中执行
new Thread(() -> {
try {
String url = "https://your-api-domain.com/api/users";
OkHttpClient client = new OkHttpClient();
// 构建请求体
MediaType JSON = MediaType.get("application/json; charset=utf-8");
String jsonBody = "{\"name\":\"张三\",\"email\":\"zhangsan@example.com\"}";
RequestBody body = RequestBody.create(jsonBody, JSON);
// 构建请求
Request request = new Request.Builder()
.url(url)
.post(body) // .post() 用于发送请求体
.build();
// 发送请求并获取响应
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
// 获取响应体字符串
String responseData = response.body().string();
System.out.println("Server Response: " + responseData);
// 在这里处理返回的数据
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
发送异步请求 (推荐方式): 异步请求不会阻塞调用线程,是处理网络请求的最佳实践。
OkHttpClient client = new OkHttpClient();
String url = "https://your-api-domain.com/api/users";
MediaType JSON = MediaType.get("application/json; charset=utf-8");
String jsonBody = "{\"name\":\"张三\",\"email\":\"zhangsan@example.com\"}";
RequestBody body = RequestBody.create(jsonBody, JSON);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
// 异步发送请求
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// 请求失败,例如网络错误、超时等
// 注意:此回调在子线程中执行
e.printStackTrace();
// 可以通过 Handler 切换到主线程更新 UI
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// 请求成功,收到服务器响应
// 注意:此回调也在子线程中执行
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
String responseData = response.body().string();
System.out.println("Server Response: " + responseData);
// 如果需要更新 UI,必须切换到主线程
// 使用 Handler, runOnUiThread, 或 LiveData
new Handler(Looper.getMainLooper()).post(() -> {
// 在这里更新 UI
// textView.setText(responseData);
});
}
});
使用 Retrofit (高级 REST API 客户端)
Retrofit 是一个类型安全的 HTTP 客户端,它将 REST API 的接口转换为 Java 接口,它内部就是基于 OkHttp 实现的,当你需要与复杂的 API 交互时,Retrofit 是不二之选。
优点:
- 类型安全:通过接口定义 API,编译时检查错误。
- 代码简洁:将 URL、请求方法、参数等通过注解清晰地定义在接口中。
- 易于维护:接口和实现分离,结构清晰。
- 自动转换:可以自动将 JSON 响应体转换成 Java 对象(需要配合 Gson/Moshi/Jackson 等库)。
第一步:添加依赖
在 app/build.gradle 中添加:
// Retrofit
implementation("com.squareup.retrofit2:retrofit:2.9.0")
// JSON 转换器 (这里以 Gson 为例)
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
// OkHttp (Retrofit 依赖它,但最好显式声明)
implementation("com.squareup.okhttp3:okhttp:4.12.0")
第二步:定义 API 接口 创建一个 Java 接口,用注解来描述 API。
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.POST;
public interface ApiService {
// @POST 定义了这是一个 POST 请求
// "api/users" 是相对路径,会与 Retrofit 实例的 baseUrl 拼接
// @Body 将方法参数自动作为请求体发送
@POST("api/users")
Call<ApiResponse> createUser(@Body User user);
}
// 定义请求体对应的 Java 对象
class User {
private String name;
private String email;
// 必须有无参构造函数,并且有 getter/setter 或使用 @SerializedName
public User(String name, String email) {
this.name = name;
this.email = email;
}
// Getter and Setter...
}
// 定义服务器响应对应的 Java 对象
class ApiResponse {
private String status;
private String message;
private String user_id;
// Getter and Setter...
}
第三步:创建 Retrofit 实例并发送请求
public class ApiClient {
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl("https://your-api-domain.com/") // 必须以 /
.addConverterFactory(GsonConverterFactory.create()) // 添加 JSON 转换器
.build();
}
return retrofit;
}
}
// 在 Activity 或其他地方调用
ApiService apiService = ApiClient.getClient().create(ApiService.class);
// 创建请求体对象
User user = new User("张三", "zhangsan@example.com");
// 发起异步请求
Call<ApiResponse> call = apiService.createUser(user);
call.enqueue(new Callback<ApiResponse>() {
@Override
public void onFailure(Call<ApiResponse> call, Throwable t) {
// 请求失败
t.printStackTrace();
}
@Override
public void onResponse(Call<ApiResponse> call, Response<ApiResponse> response) {
// 请求成功
if (response.isSuccessful()) {
ApiResponse apiResponse = response.body();
if (apiResponse != null) {
System.out.println("Status: " + apiResponse.getStatus());
System.out.println("Message: " + apiResponse.getMessage());
// 更新 UI...
}
} else {
// 处理错误响应,response.code() == 400
System.out.println("Error: " + response.code());
}
}
});
数据格式选择:JSON vs. Form-Data
-
JSON (application/json):
- 优点:结构化,易于人阅读和机器解析,是现代 Web API 的标准,适合发送复杂、嵌套的数据。
- 缺点:相比表单数据,体积稍大。
- 用法:如上所示,构建一个 JSON 字符串或对象,设置
Content-Type为application/json。
-
Form-Data (application/x-www-form-urlencoded 或 multipart/form-data):
-
优点:传统的表单提交格式,简单直接。
multipart/form-data特别适合用来上传文件。 -
缺点:不适合表示复杂的数据结构。
-
用法:
-
application/x-www-form-urlencoded(键值对):// OkHttp 示例 FormBody formBody = new FormBody.Builder() .add("name", "张三") .add("email", "zhangsan@example.com") .build(); Request request = new Request.Builder() .url("https://your-api-domain.com/api/users") .post(formBody) .build(); -
multipart/form-data(常用于文件上传):// OkHttp 示例 MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png"); File file = new File("/path/to/image.png"); RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("username", "zhangsan") .addFormDataPart("profile_picture", "image.png", RequestBody.create(file, MEDIA_TYPE_PNG)) .build(); Request request = new Request.Builder() .url("https://your-api-domain.com/api/upload") .post(requestBody) .build();
-
-
关键注意事项
- 网络权限: 别忘了在
AndroidManifest.xml中添加<uses-permission android:name="android.permission.INTERNET" />。 - 子线程: 所有网络操作都不能在主线程(UI线程)中执行,否则会抛出
NetworkOnMainThreadException异常,必须使用异步请求(如okhttp的enqueue或retrofit的enqueue)或在子线程中执行同步请求。 - 数据安全: 生产环境中,务必使用 HTTPS 协议,以防止数据在传输过程中被窃听或篡改。
- 错误处理: 妥善处理网络错误(如无连接、超时)和服务器返回的错误状态码(如 404, 500)。
- 超时设置: 对于 OkHttp,可以设置连接、读取和写入的超时时间,防止请求长时间卡住。
OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .build();
完整示例:使用 OkHttp 发送 JSON 数据
假设我们要将一个用户信息发送到服务器。
添加依赖和权限 (如上所述)
在 Activity 中调用
public class MainActivity extends AppCompatActivity {
private static final String API_URL = "https://your-api-domain.com/api/users";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendButton = findViewById(R.id.send_button);
sendButton.setOnClickListener(v -> sendData());
}
private void sendData() {
// 1. 构建要发送的 JSON 数据
String jsonBody = "{\"name\":\"李四\",\"email\":\"lisi@example.com\"}";
// 2. 创建 OkHttpClient 实例
OkHttpClient client = new OkHttpClient();
// 3. 创建 RequestBody
MediaType mediaType = MediaType.get("application/json; charset=utf-8");
RequestBody body = RequestBody.create(jsonBody, mediaType);
// 4. 创建 Request
Request request = new Request.Builder()
.url(API_URL)
.post(body)
.build();
// 5. 发送异步请求
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
// 请求失败,在子线程中执行
runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "发送失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
});
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
// 请求成功,在子线程中执行
if (response.isSuccessful()) {
String responseData = response.body().string();
runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "发送成功! 响应: " + responseData, Toast.LENGTH_LONG).show();
});
} else {
runOnUiThread(() -> {
Toast.makeText(MainActivity.this, "服务器错误: " + response.code(), Toast.LENGTH_SHORT).show();
});
}
}
});
}
}
进阶话题
- 文件上传: 如上所述,使用
MultipartBody可以轻松实现文件上传。 - 断点续传: 需要客户端记录已上传的字节数,并在请求头中 (
Range) 告诉服务器从哪里开始继续上传,OkHttp 和 Retrofit 本身不直接支持,需要自定义实现。 - 进度监听: OkHttp 本身不直接提供上传/下载进度回调,可以通过继承
RequestBody和ResponseBody并重写相关方法来实现自定义的进度监听,很多第三方库(如OkHttp-Progress)已经封装好了这个功能。
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| HttpURLConnection | 无需依赖 | 代码繁琐,功能弱 | 简单 demo 或对依赖有严格限制的项目 |
| OkHttp | 性能好,API简洁,功能强大 | 相比原生 API 仍是第三方库 | 绝大多数 Android 网络请求场景,是事实上的标准 |
| Retrofit | 类型安全,代码清晰,易于维护 | 需要学习成本,是 OkHttp 的上层封装 | 与 RESTful API 交互复杂、需要将 JSON 自动映射为 Java 对象的项目 |
对于新项目,强烈推荐直接从 Retrofit 开始,因为它能让你写出更健壮、更易于维护的代码,如果只是需要一个简单的网络工具,OkHttp 也非常优秀,尽量避免直接使用 HttpURLConnection 除非有特殊原因。
