2 网络架构的设计与实现
volley将一切的过程都封装好了,比如请求的处理、加载、缓存、线程、同步和回调等等,我们只需要简单的创建请求对象,然后便可以处理回调对象,其中的过程都已经被volley封装好了。在深入学习volley源码之前,我们先来学习一下网络架构的设计与实现。在主要框架理解之后,带着想法去看源码才是最好的方法,这样能够避免混乱找不到主线。
其实Android中的网络通信的核心其实就是两步:从url中创建Connection对象并从其中获取到输入流从而获取资源,即同步加载,该过程需要在子线程中实现;还有将获取到的数据传送至主线程显示,即异步加载显示。核心代码的最基础版本如下所示:
//创建主线程的Handler用于异步回调
Handler handler = new Handler(Looper.getMainLooper)
{
public void handleMessage(android.os.Message msg)
{
textView.setText((String)msg.obj);
};
};
//在子线程中进行网络请求
new Thread(new Runnable() {
@Override
public void run() {
try {
URL url = new URL("http://10.132.25.104/TestData/data1.php");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder sb = new StringBuilder();
String temp;
while((temp = br.readLine()) != null)
{
sb.append(temp);
}
Message msg = Message.obtain();
msg.obj = sb.toString();
handler.sendMessage(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
知道最核心的工作之后再去探索整个网络架构就有了清晰的目的了,肯定是所有的工作都是围绕着核心工作展开的,然后就是各种优化、解耦和封装,使得在使用框架的时候可以只关心传入的参数,而不用关心具体是怎么操作的。然后我们也按照着这样的思路将上面的最基础代码扩展开来。
从优化、解耦和封装的角度去思考,大概可以想到这么些扩展的思路:
- 线程池:既然用到了子线程,那么无例外地肯定想到了使用线程池来管理子线程,因此线程池是一个优化的方向;
- 请求队列(RequestQueue):通常和线程池一起搭配工作的还有请求队列RequestQueue,用于管理所提交的请求,这样线程池就能循环工作,执行完一个请求之后便从队列中取出请求继续执行,如果队列里面没有请求则会阻塞;
- 封装类(Request、Response和HttpStack):在网络通信的过程中,数据包不仅含有内容信息,还有一些首部内容,比如一些POST方式下的参数,因此可以将每次的请求封装成一个请求类Request,用于封装请求的数据;同样的,返回的数据包也可以封装成一个响应类Response,用于存储返回的数据;还有执行请求的执行类HttpStack类,它就相当于在Request和Response中间的桥梁,作用是处理Request请求类生成Http请求报文,包括了首部和内容的封装过程,还有处理返回的数据封装成HttpResponse类,注意这里是HttpResponse类,数据是以HttpEntity形式存储的,要转为Response类还要经过一层处理;
- 回调传输类(ResponseDelivery):每个请求之后的响应类都是在子线程中的,而往往这些数据需要更新在界面上,也就是需要返回到主线程中,此时便需要一个持有主线程Handler的回调传输类Delivery用于将响应数据送回主线程;
- 缓存类(Cache):网络通信中经常需要考虑的一个还有缓存问题,因为每次对网络请求都会花费时间和流量,因此通常会在第一次请求时将响应的数据缓存到磁盘和内存,之后同一个请求便可通过缓存来获取数据。
然后根据设计模式中的依赖倒置原则也就是面向接口编程,网络架构大致如下图所示:
从图中可以看出,整个网络架构的核心工作流程大概可以分为4步(不考虑缓存的情况):
- 创建Request类对象
- 添加Request对象进RequestQueue
- 线程池中的线程NetworkExecutor从队列中取出Request类交与HttpStack类执行
- 最后通过ResponseDelivery的postResponse将HttpStack解析出来的数据处理封装成Response类之后交与主线程的回调方法(一般是创建Reqeust对象时的Listener的方法)
这大致也是volley的工作流程,这里只是介绍了整个框架,下面一节我们结合volley的源码将整个流程分析一遍。