凌峰创科服务平台

Android如何调用服务器接口?

核心概念

在开始之前,我们需要了解几个基本概念:

Android如何调用服务器接口?-图1
(图片来源网络,侵删)
  1. HTTP/HTTPS 协议:Android 应用与服务器通信的基础,现在几乎所有的生产环境都使用 HTTPS,因为它通过 SSL/TLS 加密了数据,保证了数据传输的安全性。
  2. 请求方法
    • GET:用于从服务器获取数据(查询)。
    • POST:用于向服务器提交数据(创建、更新)。
    • PUT / PATCH:用于更新服务器上的数据(较少用,通常用 POST 代替)。
    • DELETE:用于删除服务器上的数据。
  3. 请求头:附加在请求上的信息,如 Content-Type (内容类型, application/json), Authorization (认证信息) 等。
  4. 请求体:POST 或 PUT 请求时发送给服务器的数据,通常是 JSON 格式。
  5. 响应:服务器返回的数据,包含状态码(如 200 成功, 404 未找到, 500 服务器错误)和响应体(通常是 JSON 数据)。

使用 HttpURLConnection (Java 原生)

这是 Android SDK 自带的方式,无需添加任何依赖,它功能强大,但 API 相对繁琐,适合简单的网络请求。

优点:

  • 无需第三方库,减少应用体积。
  • 是 Android 平台的标准 API。

缺点:

  • API 较为底层,代码冗长。
  • 处理 JSON 需要手动解析或引入额外的 JSON 库(如 org.json 或 Gson)。
  • 不支持异步操作,需要手动开启线程。

示例代码 (GET 请求)

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "NetworkDemo";
    private TextView tvResult;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvResult = findViewById(R.id.tv_result);
        // 网络请求不能在主线程(UI线程)进行,否则会抛出 NetworkOnMainThreadException
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    String response = performGetRequest("https://jsonplaceholder.typicode.com/posts/1");
                    // 更新UI必须在主线程
                    new Handler(Looper.getMainLooper()).post(new Runnable() {
                        @Override
                        public void run() {
                            tvResult.setText(response);
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    private String performGetRequest(String urlString) throws IOException {
        URL url = new URL(urlString);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setConnectTimeout(5000); // 5秒连接超时
        connection.setReadTimeout(10000);  // 10秒读取超时
        int responseCode = connection.getResponseCode();
        Log.d(TAG, "Response Code: " + responseCode);
        if (responseCode == HttpURLConnection.HTTP_OK) { // 200
            InputStream inputStream = connection.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            reader.close();
            inputStream.close();
            return response.toString();
        } else {
            return "GET request failed. Response Code: " + responseCode;
        }
    }
}

使用 OkHttp (强烈推荐)

OkHttp 是目前 Android 开发中最流行的网络请求库,它高效、易用,并内置了对现代网络协议的支持。

优点:

  • 高效:支持 HTTP/2,可以复用连接,减少延迟。
  • 易用:提供简洁的 API,支持同步和异步请求。
  • 强大:内置连接池、拦截器、GZIP 压缩等功能。
  • 现代:是 Google 官方推荐的 Android 网络库。

缺点:

  • 需要添加第三方依赖。

添加依赖

app/build.gradle 文件的 dependencies 代码块中添加:

// OkHttp
implementation("com.squareup.okhttp3:okhttp:4.12.0")
// 为了方便解析JSON,通常会搭配Gson或Moshi
implementation("com.google.code.gson:gson:2.10.1")

添加网络权限

app/src/main/AndroidManifest.xml 文件中添加:

Android如何调用服务器接口?-图2
(图片来源网络,侵删)
<uses-permission android:name="android.permission.INTERNET" />

示例代码 (异步 GET 请求)

import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.IOException;
import java.lang.reflect.Type;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class OkHttpActivity extends AppCompatActivity {
    private static final String TAG = "OkHttpDemo";
    private TextView tvResult;
    private OkHttpClient client;
    private Gson gson;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvResult = findViewById(R.id.tv_result);
        client = new OkHttpClient();
        gson = new Gson();
        // 异步GET请求
        performGetRequest();
    }
    private void performGetRequest() {
        String url = "https://jsonplaceholder.typicode.com/posts/1";
        Request request = new Request.Builder()
                .url(url)
                .build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                // 请求失败,在主线程更新UI
                runOnUiThread(() -> tvResult.setText("请求失败: " + e.getMessage()));
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    String responseBody = response.body().string();
                    Log.d(TAG, "Response: " + responseBody);
                    // 解析JSON
                    Post post = gson.fromJson(responseBody, Post.class);
                    // 在主线程更新UI
                    runOnUiThread(() -> tvResult.setText(
                            "Title: " + post.title + "\n" +
                            "Body: " + post.body
                    ));
                } else {
                    runOnUiThread(() -> tvResult.setText("请求失败: Code " + response.code()));
                }
            }
        });
    }
    // 定义一个数据模型类来匹配JSON结构
    static class Post {
        int userId;
        int id;
        String title;
        String body;
    }
}

示例代码 (异步 POST 请求)

// 在OkHttpActivity中添加此方法
private void performPostRequest() {
    String url = "https://jsonplaceholder.typicode.com/posts";
    // 创建要发送的JSON数据
    Post newPost = new Post();
    newPost.userId = 1;
    newPost.title = "新标题";
    newPost.body = "这是新发布的内容。";
    String jsonBody = gson.toJson(newPost);
    RequestBody body = RequestBody.create(jsonBody, MediaType.get("application/json; charset=utf-8"));
    Request request = new Request.Builder()
            .url(url)
            .post(body)
            .build();
    client.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            runOnUiThread(() -> tvResult.setText("POST请求失败: " + e.getMessage()));
        }
        @Override
        public void onResponse(Call call, Response response) throws IOException {
            if (response.isSuccessful()) {
                String responseBody = response.body().string();
                Log.d(TAG, "POST Response: " + responseBody);
                runOnUiThread(() -> tvResult.setText("POST成功,服务器响应: \n" + responseBody));
            } else {
                runOnUiThread(() -> tvResult.setText("POST请求失败: Code " + response.code()));
            }
        }
    });
}

使用 Retrofit (更高级的选择)

Retrofit 是一个类型安全的 HTTP 客户端,由 Square 公司(OkHttp 的开发者)打造,它将 REST API 转换为 Java 接口,极大地简化了网络请求的编写。

优点:

  • 类型安全:通过接口定义 API,编译时检查错误。
  • 代码简洁:使用注解(如 @GET, @POST, @Path)来描述请求,代码可读性极高。
  • 集成性好:默认使用 OkHttp 作为底层实现,可以无缝集成 Gson、Moshi 等库进行序列化和反序列化。
  • 支持 RxJava, Coroutines:可以轻松与响应式编程和协程结合,实现更优雅的异步处理。

缺点:

  • 学习曲线比 OkHttp 稍陡。
  • 需要添加多个依赖。

添加依赖

app/build.gradle 文件中添加:

// Retrofit
implementation("com.squareup.retrofit2:retrofit:2.9.0")
// Retrofit with Gson Converter
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
// Coroutines Support (可选,但强烈推荐)
implementation("com.squareup.retrofit2:retrofit-coroutines-adapter:0.9.2") // 或使用其他适配器

定义 API 接口

创建一个接口,用 Retrofit 的注解来描述 API。

import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
public interface ApiService {
    // GET https://jsonplaceholder.typicode.com/posts/1
    @GET("posts/{id}")
    Call<Post> getPost(@Path("id") int id);
    // POST https://jsonplaceholder.typicode.com/posts
    @POST("posts")
    Call<Post> createPost(@Body Post post);
}

创建 Retrofit 实例

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitClient {
    private static Retrofit retrofit = null;
    private static final String BASE_URL = "https://jsonplaceholder.typicode.com/";
    public static Retrofit getClient() {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}

示例代码 (使用 Retrofit)

import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class RetrofitActivity extends AppCompatActivity {
    private TextView tvResult;
    private ApiService apiService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvResult = findViewById(R.id.tv_result);
        // 1. 创建 ApiService 实例
        apiService = RetrofitClient.getClient().create(ApiService.class);
        // 2. 调用 API 方法
        getPostById(1);
    }
    private void getPostById(int id) {
        Call<Post> call = apiService.getPost(id);
        call.enqueue(new Callback<Post>() {
            @Override
            public void onResponse(Call<Post> call, Response<Post> response) {
                if (response.isSuccessful() && response.body() != null) {
                    Post post = response.body();
                    tvResult.setText(
                            "Title: " + post.title + "\n" +
                            "Body: " + post.body
                    );
                } else {
                    tvResult.setText("请求失败: Code " + response.code());
                }
            }
            @Override
            public void onFailure(Call<Post> call, Throwable t) {
                tvResult.setText("请求失败: " + t.getMessage());
            }
        });
    }
    // POST 请求调用示例
    private void createNewPost() {
        Post newPost = new Post();
        newPost.userId = 1;
        newPost.title = "Retrofit 新标题";
        newPost.body = "这是使用 Retrofit 创建的内容。";
        Call<Post> call = apiService.createPost(newPost);
        call.enqueue(new Callback<Post>() {
            @Override
            public void onResponse(Call<Post> call, Response<Post> response) {
                if (response.isSuccessful()) {
                    tvResult.setText("POST 成功: " + response.body().title);
                }
            }
            @Override
            public void onFailure(Call<Post> call, Throwable t) {
                tvResult.setText("POST 失败: " + t.getMessage());
            }
        });
    }
}

最佳实践与注意事项

  1. 禁止在主线程进行网络请求

    Android如何调用服务器接口?-图3
    (图片来源网络,侵删)
    • Android 4.0 (API level 11) 之后,禁止在主线程(UI 线程)执行网络操作,否则会抛出 NetworkOnMainThreadException 异常。
    • 解决方案:使用 AsyncTask (已废弃)、Thread + HandlerExecutorService,或者更现代的 Kotlin CoroutinesRxJava
  2. 处理网络状态

    • 在发起请求前,最好检查设备是否连接了网络。
    • 可以使用 ConnectivityManagerNetworkCapabilities 来检查网络连接状态。
  3. 使用 HTTPS

    现代应用必须使用 HTTPS 来保护数据安全,防止中间人攻击。

  4. 数据解析

    • 推荐使用 GsonMoshiJackson 等 JSON 库来解析数据,而不是手动拼接字符串,Retrofit 和 OkHttp 都可以很方便地集成它们。
  5. 异常处理

    网络请求可能因为各种原因失败(无网络、服务器宕机、超时等),务必做好异常处理,并向用户友好的提示。

  6. 生命周期管理

    • 当 Activity 或 Fragment 在网络请求返回之前被销毁时,应取消对应的网络请求,以避免内存泄漏和无效的 UI 更新,Retrofit 的 Call 对象提供了 cancel() 方法。

总结与选择

特性 HttpURLConnection OkHttp Retrofit
易用性 低 (代码繁琐) 中 (API 简洁) 高 (接口驱动)
功能 基础 强大 (连接池,拦截器) 非常强大 (类型安全,易扩展)
依赖 1 个 2-3 个
适用场景 简单、轻量级项目;不想引入第三方库时 绝大多数 Android 项目的首选 大型、复杂的 RESTful API 项目;追求代码优雅和类型安全

推荐路线:

  • 初学者或简单项目:可以直接使用 HttpURLConnection 了解原理,但更推荐直接上手 OkHttp
  • 标准开发:直接使用 OkHttp + Gson 是一个非常健壮和流行的组合。
  • 专业开发/大型项目:强烈推荐 Retrofit,它能让你写出更规范、更易于维护和测试的代码,是现代 Android 开发的行业标准。
分享:
扫描分享到社交APP
上一篇
下一篇