上一篇
安卓从服务器获取数据
- 行业动态
- 2025-04-24
- 2
安卓通过HttpURLConnection/OkHttp发起网络请求,向服务器发送GET/POST请求,获取JSON/XML等格式数据,需在子线程处理并解析,注意权限声明与异常捕获
常见网络请求方式
基础HTTP请求
- 使用
HttpURLConnection
或OkHttp
发起请求 - 需手动处理连接、输入输出流、异常捕获
- 适合简单请求,但代码冗余
- 使用
第三方网络库
| 库名 | 特点 |
|————|———————————————————————-|
| Retrofit | 基于OKHttp,支持注解式接口定义,自动解析JSON/XML,链式调用 |
| Volley | 谷歌出品,适合小数据量传输,内置缓存机制,支持ImageLoader |
| OkGo | 国人开发,支持多种缓存策略,兼容低版本Android系统 |协程+网络库
- Kotlin协程可简化异步代码(如
suspendCancellableCoroutine
) - 示例:
Retrofit + CoroutineAdapterFactory
实现挂起函数
- Kotlin协程可简化异步代码(如
核心实现步骤
添加网络权限
<uses-permission android:name="android.permission.INTERNET" />
创建Retrofit实例
val retrofit = Retrofit.Builder() .baseUrl("https://api.example.com/") .addConverterFactory(GsonConverterFactory.create()) .build()
定义API接口
interface ApiService { @GET("users/{id}") suspend fun getUser(@Path("id") userId: Int): Response<User> }
异步调用接口
viewModelScope.launch { try { val user = apiService.getUser(123) _userLiveData.postValue(user) } catch (e: Exception) { // 处理异常 } }
关键注意事项
线程管理
- 必须使用
ViewModel
/Lifecycle
组件或协程保证生命周期安全 - 避免在
Activity/Fragment
的onDestroy
后继续回调
- 必须使用
数据解析
| 数据类型 | 推荐库 | 特点 |
|———-|———————-|————————–|
| JSON | Gson/Moshi | 支持注解、泛型 |
| XML | SimpleXML | 流式解析,节省内存 |
| Protobuf| Square Upleak | 高性能二进制序列化 |错误处理
- 网络不可用:
isNetworkAvailable()
检测 - HTTP错误码:根据
response.code()
处理 - 数据异常:
try-catch
包裹解析逻辑
- 网络不可用:
性能优化方案
缓存策略
- OKHttp缓存:
Cache(size, path)
配置磁盘缓存 - Room数据库:存储结构化数据,配合
LiveData
观察更新 - 内存缓存:
LruCache
实现Bitmap等临时存储
- OKHttp缓存:
请求合并
- 使用
Debounce
操作符(RxJava)或delay
(协程)合并高频请求 - 示例:搜索框输入时延迟0.5秒发送请求
- 使用
压缩与加密
- GZIP压缩:
OkHttpClient.builder().addInterceptor(gzipInterceptor)
- HTTPS证书:自签名证书需配置
TrustManager
- GZIP压缩:
相关问题与解答
Q1:如何处理嵌套JSON数组的解析?
A1:使用Gson
的TypeToken
处理泛型,或定义嵌套数据类。
data class Response(val items: List<Item>) data class Item(val id: Int, val name: String) // 解析时:Gson().fromJson(json, Response::class.java)
Q2:如何配置Retrofit的超时重试机制?
A2:通过OkHttpClient
设置拦截器:
val client = OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .retryOnConnectionFailure(true) // 启用重试 .addInterceptor { chain -> var request = chain.request() // 添加统一头信息等操作 chain.proceed(request) } .build()