一个网络库的设计与实现 JackaRain 2025-10-31 0 浏览 0 点赞 长文 本文详细介绍了一个网络库从零开始,逐步迭代和重构的设计与实现过程。作者的目标是构建一个类似于经典网络库 Volley 的轻量级框架。 ## V1: 最初的版本 最简单的网络请求实现,直接在主线程(或任何调用线程)中使用 `HttpURLConnection` 发起同步请求。 * **实现**: 创建一个 `Network` 类,包含一个 `execute(String url)` 方法,返回请求的字符串结果。 * **问题**: 1. **阻塞线程**: 直接在调用线程执行网络请求,如果在UI线程调用会引发 `NetworkOnMainThreadException` 异常。 2. **回调问题**: 需要调用者自行处理线程切换,通过 `Handler` 将结果传递回主线程更新UI,代码分散且繁琐。 ## V2: 引入请求队列与分发器 为了解决线程阻塞和回调问题,引入了请求队列(Request Queue)和请求分发器(Dispatcher)的概念。 * **架构**: 1. **RequestQueue**: 一个阻塞队列,用于存储待执行的 `Request` 对象。UI线程将请求添加到此队列中。 2. **Dispatcher**: 一个后台线程,不断地从 `RequestQueue` 中取出请求,然后执行网络操作。 3. **Request**: 封装了URL和回调接口 `Callback`。 * **流程**: UI线程创建 `Request` 对象并将其放入队列 -> `Dispatcher` 线程循环取出请求 -> 执行网络操作 -> 通过 `Handler` 将结果回调给主线程。 * **改进**: 解决了线程阻塞问题,统一了回调处理逻辑。 * **问题**: `Dispatcher` 是一个单线程,所有请求串行执行,效率低下。 ## V3: 引入线程池 为了解决V2中串行执行的效率问题,引入了线程池(ExecutorService)来并发处理请求。 * **架构**: `Dispatcher` 不再自己执行网络请求,而是将取出的请求任务提交给一个线程池。 * **流程**: `Dispatcher` 从队列取出请求 -> 将请求封装成一个 `Runnable` 任务 -> 提交给 `ExecutorService` 并发执行。 * **改进**: 实现了请求的并发处理,显著提升了效率。 ## V4: 抽象与封装 当前版本只能处理返回字符串的请求,为了支持如图、JSON等不同类型的响应,需要进行抽象和封装。 * **重构**: 1. **`Request` 类抽象化**: 将 `Request` 定义为一个抽象类,包含 `parseResponse` 抽象方法,由子类(如 `StringRequest`, `JsonRequest`)实现如何解析 `byte[]` 响应体。 2. **`Response` 类封装**: 创建一个 `Response` 类,用于封装请求成功的结果或失败的异常信息。 3. **泛型支持**: 在 `Request<T>` 和 `Callback<T>` 中使用泛型,使框架能够支持任意类型的响应。 4. **`Network` 接口**: 将网络执行逻辑抽象为 `Network` 接口,默认实现为 `HttpUrlConnNetwork`,便于未来替换底层实现(如使用OkHttp)。 * **改进**: 框架的扩展性大大增强,结构更加清晰,符合面向对象的设计原则。 ## V5: 增加缓存机制 为了减少不必要的网络请求,提升响应速度和节省流量,引入了缓存机制。 * **架构**: 1. **`Cache` 接口**: 定义缓存的 `get` 和 `put` 方法。 2. **`DiskCache` 实现**: 提供一个基于磁盘的缓存实现。 * **流程**: * `Dispatcher` 在执行网络请求前,先检查缓存中是否存在有效的响应。 * 如果缓存命中且未过期,则直接从缓存读取数据并返回,不再执行网络请求。 * 如果缓存未命中或已过期,则执行网络请求,并将成功的结果写入缓存。 * **改进**: 实现了完整的“检查缓存 -> 网络请求 -> 写入缓存”的流程,使网络库更加高效和实用。 ## 最终架构 经过多轮迭代,最终形成了一个包含 **请求队列、分发器、线程池、网络执行模块和缓存模块** 的完整网络库。其设计思想与 Volley 高度相似,展示了如何通过逐步重构来构建一个健壮、可扩展的系统。 阅读 JackaRain 原文 本文的原始来源。 #Android #多线程 #架构设计 #缓存 #网络库