Android网络请求开发全指南:从基础到高级实践

1. Android网络请求基础与权限配置

在Android开发中,网络请求是实现应用与服务器交互的核心功能。与iOS平台不同,Android的网络请求实现有其独特的机制和注意事项。我们先从最基础的权限配置开始讲起。

1.1 网络权限声明

每个需要网络访问的Android应用都必须在AndroidManifest.xml中声明以下基本权限:

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

这里有个重要细节:这两个权限都属于"普通权限"(Normal Permission),系统会在安装时自动授予,不需要运行时动态申请。这与需要用户授权的危险权限(如相机、位置等)有本质区别。

注意:即使你的应用只需要内网通信,也必须声明INTERNET权限。这是Android系统的强制要求。

1.2 网络安全配置

从Android 7.0(API 24)开始,系统默认只信任系统预装的CA证书。如果你的应用需要与使用自签名证书的服务器通信,或者需要限制可信CA的范围,就需要配置网络安全策略。

在res/xml目录下创建network_security_config.xml文件:

<network-security-config> <domain-config> <domain includeSubdomains="true">example.com</domain> <trust-anchors> <certificates src="@raw/my_ca"/> </trust-anchors> </domain-config> </network-security-config>

然后在AndroidManifest.xml中引用这个配置:

<application android:networkSecurityConfig="@xml/network_security_config" ... >

1.3 主线程限制

Android系统有个重要特性:禁止在主线程执行网络操作。如果违反这个规则,会抛出NetworkOnMainThreadException。这是因为网络请求是耗时操作,会阻塞UI线程导致应用无响应(ANR)。

解决方法通常有两种:

  1. 使用AsyncTask(已废弃,不推荐)
  2. 使用线程池或协程(推荐)

在Kotlin中,协程是最优雅的解决方案:

viewModelScope.launch { try { val result = withContext(Dispatchers.IO) { // 执行网络请求 } // 更新UI } catch (e: Exception) { // 处理异常 } }

2. 主流HTTP客户端对比与选型

Android平台提供了多种HTTP客户端实现,各有特点和适用场景。选择适合的客户端对应用的性能和开发效率至关重要。

2.1 原生HttpsURLConnection

这是Android SDK自带的HTTP客户端,支持TLS、流式上传下载等基本功能:

val url = URL("https://api.example.com/data") val connection = url.openConnection() as HttpsURLConnection try { connection.requestMethod = "GET" connection.connectTimeout = 5000 connection.readTimeout = 10000 val responseCode = connection.responseCode if (responseCode == HttpsURLConnection.HTTP_OK) { val inputStream = connection.inputStream // 处理响应数据 } } finally { connection.disconnect() }

优点:

  • 无需额外依赖
  • 系统级支持,兼容性好

缺点:

  • API较为底层,使用繁琐
  • 缺乏高级功能如自动重试、请求拦截等

2.2 OkHttp

Square公司开发的现代HTTP客户端,已成为Android开发的事实标准:

implementation 'com.squareup.okhttp3:okhttp:4.9.3'

基本用法:

val client = OkHttpClient.Builder() .connectTimeout(5, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .build() val request = Request.Builder() .url("https://api.example.com/data") .build() client.newCall(request).enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { // 处理成功响应 } override fun onFailure(call: Call, e: IOException) { // 处理失败 } })

高级特性:

  • 连接池复用
  • GZIP自动压缩
  • 响应缓存
  • 拦截器链

2.3 Retrofit

同样是Square开发的类型安全HTTP客户端,基于OkHttp:

implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

定义API接口:

interface ApiService { @GET("users/{id}") suspend fun getUser(@Path("id") id: String): User @POST("users") suspend fun createUser(@Body user: User): Response<Unit> }

创建Retrofit实例:

val retrofit = Retrofit.Builder() .baseUrl("https://api.example.com/") .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build() val apiService = retrofit.create(ApiService::class.java)

2.4 Ktor

JetBrains开发的Kotlin原生HTTP客户端:

implementation "io.ktor:ktor-client-core:2.0.0" implementation "io.ktor:ktor-client-okhttp:2.0.0"

使用示例:

val client = HttpClient(OkHttp) { install(JsonFeature) { serializer = GsonSerializer() } defaultRequest { url("https://api.example.com/") } } suspend fun getUser(id: String): User { return client.get("users/$id") }

3. 网络请求架构设计与最佳实践

良好的架构设计能让网络请求代码更易维护、测试和扩展。下面介绍几种常见的设计模式。

3.1 Repository模式

Repository层负责协调数据源(网络、数据库等),对外提供统一的数据访问接口:

class UserRepository( private val apiService: ApiService, private val userDao: UserDao ) { suspend fun getUser(id: String): User { // 先检查本地缓存 val cachedUser = userDao.getUserById(id) if (cachedUser != null) { return cachedUser } // 从网络获取 val networkUser = apiService.getUser(id) userDao.insertUser(networkUser) return networkUser } }

3.2 ViewModel与LiveData

ViewModel负责准备和管理UI相关的数据,LiveData提供数据观察能力:

class UserViewModel( private val userRepository: UserRepository ) : ViewModel() { private val _user = MutableLiveData<User>() val user: LiveData<User> = _user private val _error = MutableLiveData<String>() val error: LiveData<String> = _error fun loadUser(id: String) { viewModelScope.launch { try { val user = userRepository.getUser(id) _user.value = user } catch (e: Exception) { _error.value = "加载用户失败: ${e.message}" } } } }

3.3 依赖注入

使用依赖注入框架(如Hilt)管理网络相关依赖:

@Module @InstallIn(SingletonComponent::class) object NetworkModule { @Provides @Singleton fun provideOkHttpClient(): OkHttpClient { return OkHttpClient.Builder() .addInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY }) .connectTimeout(5, TimeUnit.SECONDS) .build() } @Provides @Singleton fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit { return Retrofit.Builder() .client(okHttpClient) .baseUrl("https://api.example.com/") .addConverterFactory(GsonConverterFactory.create()) .build() } @Provides @Singleton fun provideApiService(retrofit: Retrofit): ApiService { return retrofit.create(ApiService::class.java) } }

4. 高级网络功能实现

4.1 文件上传下载

使用OkHttp实现文件上传:

val requestBody = MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("file", file.name, file.asRequestBody("image/*".toMediaType())) .build() val request = Request.Builder() .url("https://api.example.com/upload") .post(requestBody) .build()

文件下载并显示进度:

val client = OkHttpClient.Builder() .addNetworkInterceptor { chain -> val originalResponse = chain.proceed(chain.request()) originalResponse.newBuilder() .body(originalResponse.body?.let { ProgressResponseBody(it) { bytesRead, contentLength -> val progress = (bytesRead * 100 / contentLength).toInt() // 更新进度 } }) .build() } .build()

4.2 WebSocket通信

OkHttp支持WebSocket协议:

val request = Request.Builder() .url("wss://echo.websocket.org") .build() val webSocket = client.newWebSocket(request, object : WebSocketListener() { override fun onMessage(webSocket: WebSocket, text: String) { // 处理文本消息 } override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { // 连接关闭 } }) // 发送消息 webSocket.send("Hello WebSocket!")

4.3 DNS解析优化

Android 10+支持自定义DNS解析:

val client = OkHttpClient.Builder() .dns(object : Dns { override fun lookup(hostname: String): List<InetAddress> { return try { Dns.SYSTEM.lookup(hostname) } catch (e: Exception) { // 备用DNS解析 listOf(InetAddress.getByName("1.1.1.1")) } } }) .build()

5. 网络状态监控与优化

5.1 网络状态监听

注册广播接收器监听网络变化:

val connectivityManager = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager val networkCallback = object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { // 网络可用 } override fun onLost(network: Network) { // 网络断开 } } connectivityManager.registerNetworkCallback( NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), networkCallback )

5.2 网络类型判断

检查当前网络类型:

val capabilities = connectivityManager.getNetworkCapabilities(currentNetwork) when { capabilities?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) == true -> { // WiFi网络 } capabilities?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == true -> { // 移动数据 } else -> { // 其他网络 } }

5.3 网络请求优化策略

  1. 缓存策略:合理设置Cache-Control头部
  2. 请求合并:合并多个小请求
  3. 数据压缩:使用GZIP压缩
  4. 图片优化:使用WebP格式,适当压缩
  5. 懒加载:非关键资源延迟加载
val client = OkHttpClient.Builder() .cache(Cache( directory = File(context.cacheDir, "http_cache"), maxSize = 10L * 1024 * 1024 // 10MB )) .addInterceptor(GzipRequestInterceptor()) .build()

6. 常见问题排查与调试技巧

6.1 网络请求失败排查步骤

  1. 检查网络权限是否声明
  2. 确认设备网络连接正常
  3. 使用Logcat查看详细错误信息
  4. 通过Charles或Fiddler抓包分析
  5. 检查服务器端日志

6.2 HTTPS证书问题

常见错误:

  • SSLHandshakeException
  • CertificateException

解决方案:

  1. 确认服务器证书有效
  2. 检查网络安全配置
  3. 测试时可以先暂时信任所有证书(仅限调试)
val insecureClient = OkHttpClient.Builder() .hostnameVerifier { _, _ -> true } .sslSocketFactory( createInsecureSslSocketFactory(), createInsecureTrustManager() ) .build()

警告:信任所有证书在生产环境中极其危险,务必仅在开发调试时使用。

6.3 性能优化工具

  1. Android Profiler:分析网络流量
  2. Chrome DevTools:调试WebView网络请求
  3. OkHttp EventListener:监控请求生命周期
  4. Firebase Performance Monitoring:监控网络性能
class TimingEventListener : EventListener() { override fun callStart(call: Call) { // 记录开始时间 } override fun callEnd(call: Call) { // 记录结束时间 } } val client = OkHttpClient.Builder() .eventListener(TimingEventListener()) .build()

7. 测试与Mock数据

7.1 单元测试网络请求

使用MockWebServer模拟服务器响应:

val server = MockWebServer() @Before fun setup() { server.start() } @Test fun testGetUser() = runBlocking { server.enqueue(MockResponse() .setBody("""{"id":"1","name":"Test User"}""") .setResponseCode(200)) val apiService = createApiService(server.url("/")) val user = apiService.getUser("1") assertEquals("Test User", user.name) } @After fun tearDown() { server.shutdown() }

7.2 UI测试中的网络模拟

使用IdlingResource同步测试:

@RunWith(AndroidJUnit4::class) class UserActivityTest { @get:Rule val activityRule = ActivityScenarioRule(UserActivity::class.java) @Test fun displayUserName() { val mockWebServer = MockWebServer().apply { enqueue(MockResponse() .setBody("""{"id":"1","name":"Test User"}""") .setResponseCode(200)) start() } // 注入Mock服务器URL val intent = Intent().apply { putExtra("BASE_URL", mockWebServer.url("/").toString()) } activityRule.scenario.onActivity { activity -> activity.intent = intent } // 验证UI显示 onView(withId(R.id.user_name)) .check(matches(withText("Test User"))) } }

7.3 离线模式测试

测试应用在无网络情况下的表现:

@Before fun disableNetwork() { val connectivityManager = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager val method = connectivityManager.javaClass.getDeclaredMethod( "setAirplaneMode", Boolean::class.javaPrimitiveType ) method.isAccessible = true method.invoke(connectivityManager, true) } @Test fun testOfflineBehavior() { // 验证离线状态下的UI表现 } @After fun enableNetwork() { // 恢复网络连接 }

8. 适配不同Android版本的注意事项

8.1 Android 6.0+的运行时权限

虽然网络权限不需要运行时申请,但相关权限如:

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

需要动态申请:

if (ContextCompat.checkSelfPermission( this, Manifest.permission.ACCESS_WIFI_STATE ) != PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.ACCESS_WIFI_STATE), REQUEST_CODE ) }

8.2 Android 8.0的后台限制

Android 8.0对后台服务有严格限制,长时间运行的网络任务应该:

  1. 使用JobScheduler
  2. 或WorkManager
  3. 或ForegroundService(需显示通知)
val workRequest = PeriodicWorkRequestBuilder<SyncWorker>( 1, TimeUnit.HOURS ).build() WorkManager.getInstance(context).enqueue(workRequest)

8.3 Android 9.0的明文流量限制

Android 9.0默认禁止明文HTTP流量,解决方法:

  1. 使用HTTPS
  2. 或配置网络安全策略允许特定域名使用HTTP
<network-security-config> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true">insecure.example.com</domain> </domain-config> </network-security-config>

8.4 Android 10+的隐私变更

Android 10引入的隐私变更影响网络功能:

  1. 限制获取设备MAC地址
  2. 限制访问WiFi扫描结果
  3. 限制后台启动Activity

适配建议:

  • 检查所有网络相关功能在Android 10+设备上的表现
  • 使用新的API如ConnectivityManager.NetworkCallback
  • 遵循最小权限原则

9. 性能监控与线上问题追踪

9.1 网络性能指标

关键监控指标:

  • 请求成功率
  • 平均响应时间
  • 慢请求比例
  • 流量消耗

9.2 Firebase性能监控

集成Firebase Performance Monitoring:

implementation 'com.google.firebase:firebase-perf:20.0.6'

监控特定网络请求:

val trace = FirebasePerformance.getInstance().newTrace("network_call") trace.start() // 执行网络请求 try { val response = apiService.getData() trace.putMetric("response_size", response.body()?.size() ?: 0) } finally { trace.stop() }

9.3 异常收集

使用Crashlytics收集网络相关异常:

try { // 网络请求 } catch (e: IOException) { FirebaseCrashlytics.getInstance().log("Network request failed") FirebaseCrashlytics.getInstance().recordException(e) // 处理异常 }

9.4 自定义监控系统

构建自己的监控体系:

interface NetworkMonitor { fun onRequestStart(url: String) fun onRequestSuccess(url: String, duration: Long) fun onRequestFailure(url: String, error: Throwable) } class AnalyticsNetworkMonitor : NetworkMonitor { override fun onRequestStart(url: String) { // 记录开始时间 } override fun onRequestSuccess(url: String, duration: Long) { // 上报成功指标 } override fun onRequestFailure(url: String, error: Throwable) { // 上报失败指标 } }

10. 未来趋势与新技术

10.1 HTTP/3与QUIC

HTTP/3基于QUIC协议,提供更快的连接建立和更好的移动网络性能。OkHttp已支持HTTP/3:

val client = OkHttpClient.Builder() .protocols(listOf(Protocol.HTTP_3, Protocol.HTTP_2, Protocol.HTTP_1_1)) .build()

10.2 5G网络优化

针对5G网络特点优化:

  1. 利用更高的带宽预加载更多内容
  2. 适应更低的延迟调整超时时间
  3. 使用NetworkCapabilities检测5G网络
val capabilities = connectivityManager.getNetworkCapabilities(network) if (capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_5G) == true) { // 5G网络可用,调整策略 }

10.3 边缘计算

将部分计算任务下放到边缘节点:

  1. 使用CDN边缘计算
  2. 分布式缓存策略
  3. 地理位置感知的请求路由

10.4 机器学习优化

使用机器学习预测网络行为:

  1. 预测网络质量变化
  2. 智能预加载
  3. 动态调整请求优先级
val networkQualityPredictor = NetworkQualityPredictor(context) val predictedQuality = networkQualityPredictor.predict() when (predictedQuality) { GOOD -> // 预加载更多内容 POOR -> // 只加载关键内容 }

在实际项目中,我发现网络请求的稳定性和性能对用户体验影响极大。特别是在弱网环境下,合理的重试机制、缓存策略和优雅降级能显著提升应用的可用性。建议在开发早期就建立完善的网络监控体系,这样能快速发现和解决线上问题。