当前位置: 首页 > news >正文

Android 网络请求:EasyNet(Okhttp + retrofit + flow + gson + 缓存 + 文件下载 + 文件上传 + 人性化Loading窗)

Android 网络请求:EasyNet(Okhttp + retrofit + flow + gson + 缓存 + 文件下载 + 文件上传 + 人性化Loading窗)

该模块基于 me.laujiangtao.net 网络库封装,提供了完整的网络请求功能,包括基础API调用、文件上传下载、缓存机制等。

0. 接口准备(运行本地接口测试)

在当前目录下放置待下载的文件,文件名test.zip,命令行运行 api-server-0.0.1.jar

java -jar api-server-0.0.1.jar

将手机与电脑置于同一网络环境中,源码中更改ip地址为电脑ip

1. 模块结构

net/
├── api/                    # API接口定义
│   ├── ApiService.kt       # 基础API接口
│   ├── FileApiService.kt   # 文件操作相关API接口
│   └── RawApiService.kt    # 原始数据API接口
├── base/                   # 基础类
│   └── BaseResponse.kt     # 基础响应数据类
├── HttpConst.kt            # 网络常量
├── HttpEngine.kt           # 网络请求引擎(Repository)
└── ext.kt                  # 扩展函数

2. 初始化配置

引入依赖:

repositories {...maven(url = "https://gitee.com/laujiangtao/maven-repo/raw/main/")...
}dependencies {...implementation("me.laujiangtao.net:easynet:1.0.1")...
}

在 MyApplication 中初始化网络服务:

class MyApplication : Application() {override fun onCreate() {super.onCreate()// 注册API服务HttpServiceManager.addServiceFactory("apiService") {val config = HttpConfig(HttpConst.SERVER_URL, cacheDir = cacheDir)HttpService.create<ApiService>(config)}// 注册原始数据API服务HttpServiceManager.addServiceFactory("rawApiService") {val rawConfig = HttpConfig(HttpConst.SERVER_URL, cacheDir = cacheDir, useGsonConverter = false)HttpService.create<RawApiService>(rawConfig)}// 注册文件API服务HttpServiceManager.addServiceFactory("fileApiService") {val fileConfig = HttpConfig(HttpConst.SERVER_URL, isDebug = false)HttpService.create(fileConfig, FileApiService::class.java)}}
}

3. API接口定义

3.1 基础API (ApiService.kt)

定义了基本的网络请求接口:

interface ApiService {@GET("/index/helloworld")suspend fun helloWorld(): String@GET("/index/whois")@Cacheable(ttl = 30 * 1000, strategy = CacheStrategy.CACHE_FIRST)suspend fun whois(@Query("domain") domain: String): BaseResponse<Whois?>?@GET("/index/tianqi")@Cacheable(ttl = 30 * 1000, strategy = CacheStrategy.CACHE_FIRST)suspend fun weather(@Query("city") city: String): Tianqi
}

3.2 文件操作API (FileApiService.kt)

提供了文件上传下载相关接口:

interface FileApiService {@Multipart@POST("/file/uploadFiles")suspend fun upload(@Part parts: List<MultipartBody.Part>): String?@Streaming@GET("/file/download")suspend fun downloadFile(@Query("filename") fileUrl: String): ResponseBody// ... 其他文件操作接口
}

3.3 原始数据API (RawApiService.kt)

返回原始字符串数据的接口:

interface RawApiService {@GET("/index/meinv")@Cacheable(ttl = 30 * 1000, strategy = CacheStrategy.CACHE_FIRST)suspend fun pcmeinv(): String?
}

4. 网络请求引擎 (HttpEngine.kt)

HttpEngine 是网络请求的核心类,提供了两种风格的请求方法:

4.1 Flow风格请求

class HttpEngine {// Flow风格请求方法fun getHelloWorld(): Flow<RequestStatus<String?>> = apiCall {apiService?.helloWorld()}fun whois(domain: String): Flow<RequestStatus<BaseResponse<Whois?>?>> = apiCall {apiService?.whois(domain)}fun weather(city: String): Flow<RequestStatus<Tianqi?>> {return apiCall {apiService?.weather(city)}}// 文件上传下载fun uploadFile(request: FileUploadBean): Flow<RequestStatus<String?>> {return apiCall {fileApiService?.upload(request.toMultipartParts())}}fun downloadFile(fileUrl: String): Flow<RequestStatus<ResponseBody?>> {return apiCall {fileApiService?.downloadFile(fileUrl)}}
}

4.2 挂起函数风格请求

class HttpEngine {// 挂起函数风格请求方法suspend fun getWhoIsInfo(domain: String): BaseResponse<Whois?>? {return apiService?.whois(domain)}suspend fun getTianqiInfo(city: String): Tianqi? {return apiService?.weather(city)}suspend fun getPcmeinvInfo(): String? {return rawApiService?.pcmeinv()}
}

5. ViewModel层使用

在 MyViewModel 中使用 HttpEngine:

class MyViewModel : ViewModel() {private val repository = HttpEngine()// Flow风格fun getWhoIs(domain: String, cb: ((resp: RequestStatus<BaseResponse<Whois?>?>?) -> Unit)? = null) {viewModelScope.launch(CoroutineExceptionHandler { _, _ ->cb?.invoke(null)}) {repository.whois(domain).collect { result ->cb?.invoke(result)}}}// 挂起函数风格suspend fun getWhoIsSuspend(domain: String): BaseResponse<Whois?>? {return try {withContext(Dispatchers.IO) {repository.getWhoIsInfo(domain)}} catch (e: Exception) {Log.e("UserViewModel", "获取WhoIs信息失败", e)null}}
}

6. UI层调用示例

6.1 Flow风格调用 (FlowRequestActivity.kt)

class FlowRequestActivity : MyBaseActivity<ActivityFlowRequestBinding>() {private fun setOnClick() {binding.flowRequestBaseResponse.setOnClickListener {viewModel.getWhoIs("xxhzm.cn") { result ->result?.handleBaseResponse(onDone = {showData(it.toString())},onException = {showError("异常: ${it.message}")},onStart = {showProgress()},onEnd = {hideProgress()})}}}
}

只关注成功状态

class FlowRequestActivity : MyBaseActivity<ActivityFlowRequestBinding>() {private fun setOnClick() {binding.flowRequestBaseResponse.setOnClickListener {viewModel.getWhoIs("xxhzm.cn") { result ->result?.handleBaseResponse( onDone = {showData(it.toString())})}}}
}

6.2 挂起函数风格调用 (SuspendRequestActivity.kt)

class SuspendRequestActivity : MyBaseActivity<ActivitySuspendRequestBinding>() {private fun setOnClick() {binding.requestBaseResponse.setOnClickListener {lifecycleScope.launch {showProgress()val response = viewModel.getWhoIsSuspend("xxhzm.cn")showData(response.toString())}}}
}

7. 文件操作

7.1 文件上传 (FileOperationActivity.kt)

private fun uploadFile(fileUri: MutableList<Uri?>) {try {val files = fileUri.mapNotNull { fileUri ->val file = getFileFromUri(fileUri!!)// ... 文件处理file}val params = mutableMapOf<String, String>()params["param1"] = "value1"params["param2"] = "value2"viewModel.uploadFile(files, params, "files") {handlerData(it as RequestStatus)}} catch (e: Exception) {binding.result.append("文件处理失败: ${e.message}\n")}
}

7.2 文件下载

private fun startDownload(isResume: Boolean) {val fileUrl = "test.zip"if (isResume) {// 断点续传下载viewModel.downloadFileWithResume(fileUrl, 128) {handlerDownload(it as RequestStatus)}} else {// 普通下载viewModel.downloadFile(fileUrl) {handlerDownload(it as RequestStatus)}}
}

8. 缓存机制

通过 @Cacheable 注解实现请求缓存:

@Cacheable(ttl = 30 * 1000,           // 缓存时间30秒strategy = CacheStrategy.CACHE_FIRST,  // 缓存策略includeQueryParams = true  // 包含查询参数
)
suspend fun whois(@Query("domain") domain: String): BaseResponse<Whois?>?

9. 异常处理

通过 CoroutineExceptionHandler 和 RequestStatus 处理请求状态:

result.handle(onDone = {showData(it.toString())},onException = { e ->showError("异常: ${e.message}")},onStart = {showProgress()},onEnd = {hideProgress()}
)

10. 使用建议

  1. 选择合适的请求风格:简单请求可使用挂起函数风格,复杂状态处理建议使用Flow风格
  2. 合理使用缓存:对不常变化的数据添加缓存注解提高性能
  3. 异常处理:在ViewModel和UI层都要做好异常处理
  4. 文件操作:注意文件IO操作应在后台线程执行
  5. 内存管理:及时释放不需要的资源,避免内存泄漏

Demo

通过网盘分享的文件:easynet.zip
链接: https://pan.baidu.com/s/1BSR4vpMMKnm3pCuWQB8HHQ?pwd=fh97 提取码: fh97

http://www.gsyq.cn/news/30179.html

相关文章:

  • 基于格的抗量子密码
  • Yolo11Onnx——图像后处理
  • 2025 年不锈钢方管制造厂家最新推荐排行榜:权威测评选出高性能可靠性优质品牌榜单不锈钢矩形管/不锈钢管材/不锈钢异行管/不锈钢毛细管公司推荐
  • 2025年上海机床CE认证公司权威推荐榜单:国外CE认证/快速CE认证/充电桩CE认证源头公司精选
  • 实用指南:JavaScript继承详讲
  • QEMU 建模硬件
  • P14304 【MX-J27-T1】分块
  • 2025年工业风扇厂家权威推荐榜:直流风扇、显卡散热风扇、一体机风扇、轴流风扇及散热风扇专业选购指南
  • 2025年除尘设备厂家权威推荐榜:除尘器/脉冲除尘器/中央脉冲除尘器/工业除尘器源头企业综合测评与选购指南
  • 2025年上海久宙集团:深度解析其技术护城河与行业话语权
  • 墨尔本迎来第六届PancakesCon网络安全大会
  • 2025年网络隔离变压器优质厂家权威推荐榜单:以太网变压器/网络变压器/LAN变压器源头厂家精选
  • 深入解析:使用 PyTorch 实现 CIFAR-10 图像分类:从数据加载到模型训练全流程
  • 2025年冷库保温建材工厂权威推荐榜单:泡沫模块建大棚/检修用围栏/绝缘围栏源头厂家精选
  • 《手搓》线程池
  • 单点登录的完成原理
  • 2025 年房屋改造公司最新推荐榜,聚焦企业服务能力与市场口碑深度解析老房 / 旧房 / 局部 / 小户型 / 出租房房屋改造推荐
  • 2025 年桥梁防撞护栏优质厂家最新推荐榜:涵盖锌钢 / ZF01/Q235/Q355B / 景观 / 灯光 / 河道 / 公路 / 喷塑等类型,全方位解析实力企业
  • 2025年盐趣科研教育深度解析:从录取数据到成果落地的全链路拆解
  • 大素材数据质量校验实战指南:从0.3%差异率到滴水不漏的核对体系
  • 备战CSP:考试环境搭建与使用指南
  • 2025 年防腐木厂家最新推荐排行榜:实力品牌品质测评,凉亭 / 地板 / 木屋厂家优选指南
  • 2025 年离散制造领域 MES 厂商最新推荐榜单:结合中国智能制造产业协会测评权威数据,全面揭晓优质服务商实力
  • 2025年10月中国办公家具定制公司推荐:市场报告与选择指南
  • 数字人公司:技术引领的数字人产业革新典范
  • 数字人公司|数字人服务商生态全景
  • AI|国内GEO优化公司全链路优化
  • Java-SE Day4
  • AI|AI优化公司:智能搜索时代的企业增长新引擎
  • 年度 Demo Day!见证语音 AI 年度场景诞生!丨Convo AIRTE2025