凌峰创科服务平台

Android客户端如何高效访问服务器?

核心概念:通信模式

要理解客户端和服务器是如何“对话”的,主要有两种模式:

Android客户端如何高效访问服务器?-图1
(图片来源网络,侵删)
  1. 客户端-服务器模式

    • 流程:客户端主动发起请求,服务器接收请求、处理,然后返回响应,客户端是主动方,服务器是被动响应方。
    • 例子:用户登录、刷新朋友圈、上传一张照片。
    • 技术:HTTP/HTTPS 是这种模式最常用的协议。
  2. 服务器推送模式

    • 流程:服务器主动向客户端发送消息,客户端接收并处理,服务器是主动方。
    • 例子:收到新消息、App内推送通知、订单状态更新。
    • 技术
      • 轮询:客户端定时向服务器询问是否有新消息。效率低,不推荐
      • 长连接:客户端和服务器建立一个持久的连接,服务器有消息时立即推送。
        • WebSocket:全双工通信,双方可以随时收发消息,适用于聊天、实时游戏等。
        • MQTT:轻量级的发布/订阅模式协议,专为物联网和移动端设计,非常省电,适用于消息推送、传感器数据上报等。

对于绝大多数初学者和常规App,从客户端-服务器的HTTP/HTTPS通信开始是最合适的。


数据交换格式

客户端和服务器之间传输的是纯文本,需要一种格式来组织数据,以便双方都能理解,目前最主流的是 JSON

Android客户端如何高效访问服务器?-图2
(图片来源网络,侵删)
  • JSON (JavaScript Object Notation)

    • 优点:轻量级、易于人阅读和编写、易于机器解析和生成,与JavaScript天然兼容,是Web和移动端的事实标准。
    • 示例
      {
        "userId": 123,
        "username": "张三",
        "isLoggedIn": true,
        "messages": [
          { "id": 1, "content": "你好" },
          { "id": 2, "content": "世界" }
        ]
      }
  • XML (eXtensible Markup Language)

    • 优点:结构严谨,可扩展性好。
    • 缺点:冗余信息多(标签多),解析比JSON复杂,在移动端已逐渐被JSON取代。
  • Protocol Buffers (Protobuf)

    • 优点:Google开发,序列化后数据体积小、解析速度快,性能远超JSON/XML。
    • 缺点:二进制格式,不易调试,需要先定义 .proto 文件并生成代码,适用于对性能和带宽有极致要求的场景。

除非有特殊需求,否则 首选JSON

Android客户端如何高效访问服务器?-图3
(图片来源网络,侵删)

核心技术栈

Android 端

在Android中,发送HTTP请求主要有三种方式,代表了技术的演进:

  • HttpURLConnection (原生API)

    • 优点:Android SDK内置,无需额外依赖,简单请求可以直接用。
    • 缺点:API繁琐,使用体验差,处理异步请求需要自己写线程和Handler,容易出错。
    • 适用场景:学习网络基础,或做非常简单的Demo。
  • OkHttp (强烈推荐)

    • 优点:现代、高效、功能强大,支持HTTP/2、连接池、GZIP压缩、异步/同步请求、WebSocket等,它内部已经处理了线程池,使用非常方便,目前是Android网络请求的事实标准。
    • 缺点:仅负责网络传输,不处理JSON解析等。
  • Retrofit (强烈推荐)

    • 优点:基于OkHttp,是一个类型安全的HTTP客户端,它将网络请求接口化,通过注解来描述请求,将JSON数据自动转换成Java/Kotlin对象,极大地简化了网络请求的开发,代码非常清晰、可维护性高。
    • 工作原理:Retrofit负责定义接口和解析响应,OkHttp负责执行网络请求,它们是天作之合。
    • 适用场景:几乎所有生产环境的项目。

推荐组合:Retrofit + OkHttp + Gson/Moshi

  • Retrofit: 负责将接口定义转化为网络请求。
  • OkHttp: 负责执行真正的网络IO操作。
  • Gson/Moshi: 负责JSON字符串和Java/Kotlin对象之间的序列化与反序列化。

服务器端

服务器端技术选型非常广泛,取决于你的团队技术栈和项目规模。

  • Java: Spring Boot (最流行)、Javalin、SparkJava
  • Kotlin: Ktor (JetBrains出品,与Android开发无缝衔接)、Spring Boot
  • Node.js: Express.js、Koa.js
  • Python: Django、Flask、FastAPI
  • Go: Gin、Beego
  • PHP: Laravel、ThinkPHP

对于Android开发者来说,Java或Kotlin 的后端技术栈是最容易上手的。


实战演练:使用Retrofit访问服务器

假设我们的服务器有一个获取用户信息的API:GET https://api.example.com/users/123,返回JSON数据。

第1步:添加依赖 (build.gradle.kts / build.gradle)

// build.gradle (Groovy)
// OkHttp
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
// Retrofit的Gson转换器
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
// OkHttp的日志拦截器 (方便调试)
implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'

第2步:添加网络权限 (AndroidManifest.xml)

<uses-permission android:name="android.permission.INTERNET" />

注意:从Android 9 (API 28) 开始,默认禁止HTTP明文传输,建议服务器使用HTTPS,如果必须用HTTP,需要在application标签下添加: android:usesCleartextTraffic="true"

第3步:创建数据模型

根据服务器返回的JSON,创建一个Kotlin/Java数据类。

// User.kt
data class User(
    val userId: Int,
    val username: String,
    val email: String
)

第4步:定义Retrofit API接口

使用Retrofit的注解来描述API。

import retrofit2.http.GET
import retrofit2.http.Path
// 定义一个接口来描述我们的API
interface ApiService {
    // GET请求,路径是 "/users/{userId}"
    // {userId} 是一个路径参数
    @GET("users/{userId}")
    suspend fun getUser(@Path("userId") userId: Int): User // 使用 suspend 函数支持协程
}

第5步:创建Retrofit实例并进行网络请求

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object RetrofitClient {
    // 1. 创建Retrofit实例
    private const val BASE_URL = "https://api.example.com/" // 注意:末尾的斜杠
    val instance: ApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create()) // 添加Gson转换器
            .build()
            .create(ApiService::class.java)
    }
}
// 在ViewModel或Activity/Fragment中使用
class MyViewModel : ViewModel() {
    private val _user = MutableLiveData<User>()
    val user: LiveData<User> = _user
    fun fetchUser(userId: Int) {
        // 在协程中发起网络请求,避免阻塞主线程
        viewModelScope.launch {
            try {
                val response = RetrofitClient.instance.getUser(userId)
                _user.postValue(response)
            } catch (e: Exception) {
                // 处理错误,例如网络异常、服务器错误等
                e.printStackTrace()
            }
        }
    }
}

最佳实践与注意事项

  1. 不要在主线程进行网络请求

    • Android 4.0 (API 13) 之后,网络操作必须在子线程中进行,否则会抛出 NetworkOnMainThreadException 异常。
    • 现代解决方案:使用 Kotlin CoroutinesRxJava 来处理异步逻辑,代码更简洁、更安全。
  2. 处理异步回调

    网络请求是耗时的,不能立即返回结果,必须使用异步机制(如回调、LiveData、Flow、RxJava)来更新UI。

  3. 安全性

    • HTTPS:生产环境必须使用HTTPS,防止数据在传输过程中被窃听或篡改。
    • 数据校验:不要盲目信任服务器返回的数据,在客户端进行必要的校验。
    • API密钥:不要将API密钥等敏感信息硬编码在客户端代码中,可以通过动态下发、签名等方式增加安全性。
  4. 错误处理

    处理各种可能的错误:网络连接失败、服务器返回错误码(如404, 500)、JSON解析失败等,向用户友好的提示错误信息。

  5. 性能优化

    • 缓存:对于不经常变化的数据(如配置信息),可以使用OkHttp的缓存机制,减少网络请求。
    • 连接池:OkHttp默认使用连接池,复用TCP连接,减少握手开销,提升性能。
  6. 遵守平台规范

    • 从Android 10 (API 29) 开始,默认使用非空的 executor 来执行网络请求,确保后台任务不会长期持有主线程的引用。

进阶主题

  • 身份认证
    • OAuth2:用于第三方登录(如微信、QQ登录)。
    • JWT (JSON Web Token):一种无状态的认证方式,客户端在登录后获得一个Token,后续请求在Header中携带此Token即可。
  • 文件上传/下载
    • Retrofit通过 @Multipart@Part 注解支持多部分表单上传文件。
    • 对于大文件下载,可以使用OkHttp的 ResponseBody 进行流式处理,避免内存溢出。
  • 服务端推送
    • 当需要实时功能时,可以研究 WebSocketMQTT,Retrofit本身不支持WebSocket,但有专门的 retrofit2:adapter-rxjavaretrofit2:adapter-java8 (配合CompletableFuture) 可以集成,或者使用专门的库如 OkHttp WebSocketAndroid-WebSocket-Client

希望这份详细的指南能帮助你顺利开启Android客户端与服务器通信的旅程!从Retrofit开始是一个非常好的选择。

分享:
扫描分享到社交APP
上一篇
下一篇