乘风破浪

Volley源码解析

基于”我们不重复造轮子不表示我们不需要知道轮子该怎么造及如何更好的造”,我开始了我的拆轮子之旅。
从使用方法出发我带大家跟着我的思路分析一遍volley1.1.0的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//创建请求队列
RequestQueue queue = Volley.newRequestQueue(this);
String url = "https://www.baidu.com";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
queue.add(stringRequest);

RequestQueue 一个带有线程池调度的请求分派队列
StringRequest 请求的封装,将url的response body作为String返回

我们来逐行分析上面源码

1
2
3
public static RequestQueue newRequestQueue(Context context) {
return newRequestQueue(context, (BaseHttpStack) null);
}

传入了一个null的 BaseHttpStack 类
这里可见Volley的扩展性,可以修改网络传输层,例如扩展 OkHttpStack,用okHttp作为传输层。

再看 newRequestQueue(context, (BaseHttpStack) null)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public static RequestQueue newRequestQueue(Context context, BaseHttpStack stack) {
BasicNetwork network;
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
network = new BasicNetwork(new HurlStack());
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
// At some point in the future we'll move our minSdkVersion past Froyo and can
// delete this fallback (along with all Apache HTTP code).
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {
}
network = new BasicNetwork(
new HttpClientStack(AndroidHttpClient.newInstance(userAgent)));
}
} else {
network = new BasicNetwork(stack);
}
return newRequestQueue(context, network);
}

HurlStack和HttpClientStack 都继承BaseHttpStack抽象类,发起Http请求,HurlStack使用HttpURLConnection执行网络请求,
HttpClientStack使用HttpClient执行网络。
HttpURLConnection比起HttpClient来说更加简单易用,修复了之前的bug。
从Android4.4开始HttpURLConnection的底层实现采用的okHttp。

BasicNetwork 通过对HttpStack的封装,执行网络请求, 看下调用的另一个重载的构造函数。

1
2
3
4
5
6
7
8
9
private static RequestQueue newRequestQueue(Context context, Network network) {
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();
return queue;
}
public RequestQueue(Cache cache, Network network) {
this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}

创建文件缓存路径,传入一个 DEFAULT_NETWORK_THREAD_POOL_SIZE 常量大小为4,顾名思义是默认网络线程池大小。

接着往下看

1
2
3
4
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(cache, network, threadPoolSize,
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}

这里创建了一个ExecutorDelivery对象,利用Handler把结果回调到主线中。
后面用到时候再看具体实现

接着看上面构造函数中调用的 queue.start()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
//开启4个网络调度线程
networkDispatcher.start();
}
}

调用了 CacheDispatcher的start方法和NetworkDispatcher的start方法, CacheDispatcher和NetworkDispatcher都是
Thread的子类

下面看 queue.add(stringRequest) 源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Adds a Request to the dispatch queue.
* @param request The request to service
* @return The passed-in request
*/
public <T> Request<T> add(Request<T> request) {
//将请求标记为属于该队列,并将其添加到当前请求集。
request.setRequestQueue(this);
synchronized (mCurrentRequests) {
mCurrentRequests.add(request);
}
//按照添加的顺序处理请求。
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
//如果该请求是不可缓存的,跳过缓存队列并直接进入网络。
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
mCacheQueue.add(request);
return request;
}

mCacheQueue、mNetworkQueue都是PriorityBlockingQueue>类型,PriorityBlockingQueue: 优先级阻塞队列。