君子曰:学不可以已。青,取之于蓝,而青于蓝;冰,水为之,而寒于水。
总是幻想能在技术的道路上更进一步,可大多数时候总是提不起动力,最近公司闲来无事,便开始浏览各种博客,受益良多,便突发奇想写一栏自己的博客,说来惭愧,虽从业时间不短,但在android领域依然是一位技术小白,机缘巧合下看到一位大神写的网络框架解析,受到启发,于是苦心钻研了volley框架的源码,略有所得,分享给大家。
另外,这篇文章适合于像我这样的技术小白,如果你是大神,请无视。
volley框架是2013年Google I/O大会上发布的一款android平台轻量级网络通信库,能使网络通信更快,更简单,更健壮,特别适合数据量不大但是通信频繁的场景,下面进入正题,首先我们先看看volley的使用:
RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);
StringRequest stringRequest = new StringRequest("http://www.baidu.com", new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.d("TAG", response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("TAG", error.getMessage(), error);
}
});
mQueue.add(stringRequest);
上面是一个volley的get请求,volley的使用非常简单,从Volley这个静态方法的工具类中获取RequestQueue,这是一个队列用来调度所有的Request,StringRequest是Request的一个具体实现子类,三个参数分别是请求的URL,请求成功的回调,请求失败的回调,最后将request加入RequestQueue就完成了网络请求。
我们从源头入手,先看看Volley这个工具类是如何实现的,下面是源码:
public static RequestQueue newRequestQueue(Context context) {
return newRequestQueue(context, null);
}
我们可以看到该方法是调用了另一个同名的重载方法,好,让我们继续往下看:
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
// 定义缓存路径
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {
}
// 根据版本使用HttpStack,实际上就是对HttpClient或HttpURLConnection的封装
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
// 网络接口的基本实现,处理网络请求或失败重试
Network network = new BasicNetwork(stack);
// 请求队列,处理缓存与网络交互
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();
return queue;
}
这里就是newRequestQueue方法的具体实现了,让我们一句一句慢慢分析,首先创建的File文件是一个缓存路径,用来保存需要缓存的请求成功后的返回数据,userAgent 是一个请求代理的标识,用于AndroidHttpClient的创建,stack 是我们传进来的参数,默认为null,可以看到源码根据当前api决定使用哪一种网络请求,api低于9使用HttpClientStack,高于9则使用HurlStack,而这两个类正是HttpClient与HttpURLConnection的封装,如果这两个类大家都不想使用,自己在外部创建传入也是可以的,因为这个方法也是一个静态公开的方法,之后就是创建网络处理类与缓存处理类,再传入RequestQueue中,启动这个队列让其工作,然后将RequestQueue返回。
到这里大家可能会有很多疑惑,比如HurlStack,HttpClientStack,BasicNetwork,DiskBasedCache都是什么鬼等等,别急,这篇博客会一一说道,下面我们再来看看RequestQueue源码:
public RequestQueue(Cache cache, Network network) {
this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}
大家还记得吧,我们创建RequestQueue时就传入了这两个参数,它是调用了另一个构造方法,DEFAULT_NETWORK_THREAD_POOL_SIZE的默认值是4,用于决定开启多少条网络调度线程,再往下看:
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(cache, network, threadPoolSize,
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
ExecutorDelivery类是Volley框架中的结果分发类,传入Handler以为了能够让需要的方法跑在主线程,我们也先放一放,接着看:
public RequestQueue(Cache cache, Network network, int threadPoolSize,
ResponseDelivery delivery) {
mCache = cache;
mNetwork = network;
mDispatchers = new NetworkDispatcher[threadPoolSize];
mDelivery = delivery;
}
RequestQueue的构造方法,最终到这里来,将缓存处理类,网络处理类,网络调度类,结果分发类用成员变量给予保存,threadPoolSize的值就是之前我们说的4,在上面我们分析了Volley类的源码,RequestQueue被创建后,随即调用了start方法,接着我们看看start做了什么:
public void start() {
stop(); // Make sure any currently running dispatchers are stopped.
// Create the cache dispatcher and start it.
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
// Create network dispatchers (and corresponding threads) up to the pool size.
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
public void stop() {
if (mCacheDispatcher != null) {
mCacheDispatcher.quit();
}
for (int i = 0; i < mDispatchers.length; i++) {
if (mDispatchers[i] != null) {
mDispatchers[i].quit();
}
}
}
quit方法我们暂时不说,大家理解为一个暂停线程的方法即可,mCacheDispatcher 与networkDispatcher分别是缓存调度与网络调度,我们可以明确的看出,这里开启了一条缓存调度与4条网络调度,如果有人疑惑为什么是4条?那你请回看RequestQueue的构造方法的源码。