再回首 -- Volley源码解析

前言

前面解析了Retrofit和OkHttp这两个框架的源码,提到网络框架,肯定少不了Volley这位老前辈,想曾经的项目用的可都是Volley,每个框架都有其适用的场景,只是随着时间的更迭,逐渐被替代。 那这次顺便也解析下Volley框架的源码,这里做个笔记

本篇的Volley版本基于 1.2.0-SNAPSHOT

Volley库地址

1.首先看下Volley的基本使用


	//第1步.创建RequestQueue(请求队列)
	RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());

    //第2步.创建所需的Request(请求),这里是创建StringRequest 
	StringRequest mStringRequest = 
				new StringRequest(Request.Method.GET, "http://www.baidu.com",
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        Log.i("wangshu", response);
                    }
                }, new Response.ErrorListener() {
		            @Override
		            public void onErrorResponse(VolleyError error) {
		                Log.e("wangshu", error.getMessage(), error);
		            }
        		});

	//第3步.将请求添加进请求队列中
    mQueue.add(mStringRequest);

2.从Volley的基本使用API入手其源码:

a. 首先看下创建RequestQueue的代码,由Volley.newRequestQueue开始


	public class Volley {

		public static RequestQueue newRequestQueue(Context context) {
			//调用下面标注1的newRequestQueue
	        return newRequestQueue(context, (BaseHttpStack) null);
	    }
	
		//标注1
		public static RequestQueue newRequestQueue(Context context, BaseHttpStack stack) {
	        BasicNetwork network;
	        if (stack == null) {
	            if (Build.VERSION.SDK_INT >= 9) {
	                //Android版本大于2.3,则创建基于HttpUrlConnection的HurlStack
	                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, /* flags= */ 0);
	                    userAgent = packageName + "/" + info.versionCode;
	                } catch (NameNotFoundException e) {
	                }
	                //Android版本小于2.3,则创建基于HttpClient的HttpClientStack
	                network =
	                        new BasicNetwork(
	                                new HttpClientStack(AndroidHttpClient.newInstance(userAgent)));
	            }
	        } else {
	            //stack != null的情况
	            network = new BasicNetwork(stack);
	        }

			//调用下面标注2的newRequestQueue
	        return newRequestQueue(context, network);
	    }


		//标注2
		private static RequestQueue newRequestQueue(Context context, Network network) {
	        final Context appContext = context.getApplicationContext();
	        // Use a lazy supplier for the cache directory so that newRequestQueue() can be called on
	        // main thread without causing strict mode violation.
	        DiskBasedCache.FileSupplier cacheSupplier =
	                new DiskBasedCache.FileSupplier() {
	                    private File cacheDir = null;
	
	                    @Override
	                    public File get() {
	                        if (cacheDir == null) {
	                            cacheDir = new File(appContext.getCacheDir(), DEFAULT_CACHE_DIR);
	                        }
	                        return cacheDir;
	                    }
	                };
	        RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheSupplier), network);
	        queue.start();
	        return queue;
	    }
	}

结合代码和注释,Volley.newRequestQueue主要做了两件事

  • 判断Android的系统版本是否大于2.3; Android版本大于或等于2.3,则创建基于HttpUrlConnection的HurlStack。 Android版本小于2.3,则创建基于HttpClient的HttpClientStack
  • 创建请求队列RequestQueue,并调用其start函数,最后返回RequestQueue

接着进去RequestQueue的start 函数


	public class RequestQueue {

		public void start() {
	        //将当前正在执行的线程全部中断
	        stop(); 
	        //创建缓存线程并且启动它
	        mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
	        mCacheDispatcher.start();
	
	        
	        // mDispatchers数组默认动态初始化长度为4,所以网络执行线程默认创建4条
	        for (int i = 0; i < mDispatchers.length; i++) {
	            NetworkDispatcher networkDispatcher =
	                    new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery);
	            mDispatchers[i] = networkDispatcher;
	            networkDispatcher.start();
	        }
	    }
	}

在RequestQueue的start 函数中,初始化一个缓存调度线程(CacheDispatcher)和4个( 默认情况下 ) 网络调度线程(NetworkDispatcher),所以Volley默认情况下会在后台开启5个线程。线程都初始化之后,分别调用其start方法开启线程

b. 接着看下第2步创建的StringRequest类,看下StringRequest两个核心的函数


	public class StringRequest extends Request<String> {

		//deliverResponse主要负责回调响应数据
	    @Override
	    protected void deliverResponse(String response) {
	
	        Response.Listener<String> listener;
	        synchronized (mLock) {
	            listener = mListener;
	        }
	        if (listener != null) {
	            listener.onResponse(response);
	        }
	    }
	
	    //负责解析响应数据
	    @Override
	    @SuppressWarnings("DefaultCharset")
	    protected Response<String> parseNetworkResponse(NetworkResponse response) {
	        String parsed;
	        try {
	            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
	        } catch (UnsupportedEncodingException e) {
	            // Since minSdkVersion = 8, we can't call
	            // new String(response.data, Charset.defaultCharset())
	            // So suppress the warning instead.
	            parsed = new String(response.data);
	        }
	        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
	    }
	}

可以看到StringRequest类的代码很简洁,deliverResponse函数负责将响应结果进行回调,parseNetworkResponse函数解析响应数据为Response实例,这里先记住deliverResponse和parseNetworkResponse这两个函数,后面会再碰到这个函数

c.将请求添加进请求队列中


	public class RequestQueue {

		public <T> Request<T> add(Request<T> request) {

	        request.setRequestQueue(this);
	        synchronized (mCurrentRequests) {
	            mCurrentRequests.add(request);
	        }
	
	        // Process requests in the order they are added.
	        request.setSequence(getSequenceNumber());
	        request.addMarker("add-to-queue");
	        //发送request生命周期事件
	        sendRequestEvent(request, RequestEvent.REQUEST_QUEUED);
	
	        /**
	         * 如果这个request不支持缓存,那将直接添加到网络请求队列中,并返回这个request
	         * request.shouldCache() 默认为true,即开启缓存
	         */
	        if (!request.shouldCache()) {
	            mNetworkQueue.add(request);
	            return request;
	        }
	        //request支持缓存,则添加到缓存队列中
	        mCacheQueue.add(request);
	        return request;
	    }
	}

在add函数中主要通过request.shouldCache()判断是否支持缓存,不支持缓存则将request添加进mNetworkQueue(网络请求队列),支持缓存的话则将request添加到mCacheQueue(缓存队列); request.shouldCache( )默认情况下为true,即开启缓存

在上面的代码中,可以了解到:

  • 默认情况下,是将请求添加到缓存队列中
  • Volley中主要维护了了1个缓存调度线程(CacheDispatcher),和4个(默认情况下) 网络调度线程(NetworkDispatcher)

请求添加到缓存队列,我们就从缓存调度线程(CacheDispatcher)入手

3.CacheDispatcher的工作流程

CacheDispatcher继承自Thread,那核心自然是run函数.


	public class CacheDispatcher extends Thread {

		@Override
	    public void run() {
	        if (DEBUG) VolleyLog.v("start new dispatcher");
	        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
	
	        // Make a blocking call to initialize the cache.
	        mCache.initialize();
	
	        while (true) {
	            try {
	                processRequest();
	            } catch (InterruptedException e) {
	                // We may have been interrupted because it was time to quit.
	                if (mQuit) {
	                    Thread.currentThread().interrupt();
	                    return;
	                }
	                VolleyLog.e(
	                        "Ignoring spurious interrupt of CacheDispatcher thread; "
	                                + "use quit() to terminate it");
	            }
	        }
	    }
	}	

在run函数中开启了死循环,不断执行processRequest函数


	private void processRequest() throws InterruptedException {
        
        //从缓存队列中取出请求
        final Request<?> request = mCacheQueue.take();
        processRequest(request);
    }


	@VisibleForTesting
    void processRequest(final Request<?> request) throws InterruptedException {
        request.addMarker("cache-queue-take");
        request.sendEvent(RequestQueue.RequestEvent.REQUEST_CACHE_LOOKUP_STARTED);

        try {
            // If the request has been canceled, don't bother dispatching it.
            if (request.isCanceled()) {
                request.finish("cache-discard-canceled");
                return;
            }

            // Attempt to retrieve this item from cache.
            Cache.Entry entry = mCache.get(request.getCacheKey());
            if (entry == null) {
                request.addMarker("cache-miss");
                // Cache miss; send off to the network dispatcher.
                //返回true则表示之前有执行过该请求,属于重复请求
                if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
                    mNetworkQueue.put(request);
                }
                return;
            }

            // If it is completely expired, just send it to the network.
            //true表示 缓存已到有效期
            if (entry.isExpired()) {
                request.addMarker("cache-hit-expired");
                request.setCacheEntry(entry);
                //返回true则表示之前有执行过该请求,属于重复请求
                if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
                    mNetworkQueue.put(request);
                }
                return;
            }

            // We have a cache hit; parse its data for delivery back to the request.
            request.addMarker("cache-hit");
            Response<?> response =
                    request.parseNetworkResponse(
                            new NetworkResponse(entry.data, entry.responseHeaders));
            request.addMarker("cache-hit-parsed");
            /**
             * 判断缓存的数据是否解析成功
             * JsonObjectRequest的parseNetworkResponse函数中,解析失败的话会对Response类的error变量设置值
             * response.isSuccess()则是判断error变量是否为null
             */
            if (!response.isSuccess()) { //缓存数据解析失败的情况
                request.addMarker("cache-parsing-failed");
                mCache.invalidate(request.getCacheKey(), true);
                request.setCacheEntry(null);
                //返回true则表示之前有执行过该请求,属于重复请求
                if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
                    mNetworkQueue.put(request);
                }
                return;
            }
            //缓存是否需要更新
            if (!entry.refreshNeeded()) {//不需要更新缓存的情况
                // Completely unexpired cache hit. Just deliver the response.
                //mDelivery的默认实现类是ExecutorDelivery,在RequestQueue类的构造函数中赋值的
                //在ExecutorDelivery的postResponse函数中将子线程切换到主线程,并回调给Response.Listener的onResponse()方法
                mDelivery.postResponse(request, response);
            } else {//需要更新缓存的情况
                // Soft-expired cache hit. We can deliver the cached response,
                // but we need to also send the request to the network for
                // refreshing.
                request.addMarker("cache-hit-refresh-needed");
                request.setCacheEntry(entry);
                // Mark the response as intermediate.
                response.intermediate = true;
                //返回true则表示之前有执行过该请求,属于重复请求
                if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
                    // Post the intermediate response back to the user and have
                    // the delivery then forward the request along to the network.
                    //进行网络请求
                    mDelivery.postResponse(
                            request,
                            response,
                            new Runnable() {
                                @Override
                                public void run() {
                                    try {
                                        mNetworkQueue.put(request);
                                    } catch (InterruptedException e) {
                                        // Restore the interrupted status
                                        Thread.currentThread().interrupt();
                                    }
                                }
                            });
                } else {//重复请求的情况
                    // request has been added to list of waiting requests
                    // to receive the network response from the first request once it returns.
                    //将数据回调给主线程 (Response.Listener的onResponse()方法 )
                    mDelivery.postResponse(request, response);
                }
            }
        } finally {
            request.sendEvent(RequestQueue.RequestEvent.REQUEST_CACHE_LOOKUP_FINISHED);
        }
    }

processRequest函数中大致做了如下几个判断:

  1. processRequest函数从缓存队列中取出请求,然后判断该请求是否被取消?
    • 如果取消,则直接中止该函数;
  2. 如果没有取消,则判断该请求是否有对应的缓存?
    • 如果没有缓存,则判断该请求是否已执行过,执行过则直接中止该函数,未执行过则添加到网络请求队列并中止该函数
  3. 如果有缓存,则判断该缓存是否过期?
    • 如果已过期,则判断该请求是否已执行过,执行过则直接中止该函数,未执行过则添加到网络请求队列并中止该函数
  4. 如果未过期,则解析缓存的数据,接着判断缓存数据是否解析成功?
    • 如果解析失败,则设置缓存无效,并判断该请求是否已执行过,执行过则直接中止该函数,未执行过则添加到网络请求队列并中止该函数
  5. 如果解析成功,接着判断该缓存是否需要更新?
    • 如果不需要更新,则将第4步中缓存数据解析的结果回调给主线程
  6. 如果需要更新,则判断该请求是否已执行过?
    • 如果该请求已执行过,将第4步中缓存数据解析的结果回调给主线程
    • 如果该请求未执行过,将第4步中缓存数据解析的结果回调给主线程,并将请求添加到网络请求队列中

processRequest函数中调用request.parseNetworkResponse()解析缓存的数据, request是从缓存队列中取出的,所以这个request就是一开始API中调用mQueue.add() 添加到缓存队列的StringRequest,而StringRequest类的parseNetworkResponse函数在上面已经提到,是用于将响应数据解析为Response实例的

4.NetworkDispatcher的工作流程

NetworkDispatcher同样继承自Thread,run函数同样是开启了死循环,不断执行processRequest函数


	public class NetworkDispatcher extends Thread {

		private void processRequest() throws InterruptedException {
	        //从网络队列中取出请求
	        Request<?> request = mQueue.take();
	        processRequest(request);
	    }


		@VisibleForTesting
	    void processRequest(Request<?> request) {
	        long startTimeMs = SystemClock.elapsedRealtime();
	        request.sendEvent(RequestQueue.RequestEvent.REQUEST_NETWORK_DISPATCH_STARTED);
	        try {
	            request.addMarker("network-queue-take");
	
	            // If the request was cancelled already, do not perform the
	            // network request.
	            if (request.isCanceled()) {
	                request.finish("network-discard-cancelled");
	                request.notifyListenerResponseNotUsable();
	                return;
	            }
	
	            addTrafficStatsTag(request);
	
	            // Perform the network request.
	            // 请求网络
	            NetworkResponse networkResponse = mNetwork.performRequest(request);
	            request.addMarker("network-http-complete");
	
	            // If the server returned 304 AND we delivered a response already,
	            // we're done -- don't deliver a second identical response.
	            //如果服务端响应码是304 && 该请求已经请求过,则取消该次请求
	            //在下面的代码中request.markDelivered()会将该请求设置为已请求状态
	            if (networkResponse.notModified && request.hasHadResponseDelivered()) {
	                request.finish("not-modified");
	                request.notifyListenerResponseNotUsable();
	                return;
	            }
	
	            // Parse the response here on the worker thread.
	            //在工作线程上解析服务端的响应数据
	            Response<?> response = request.parseNetworkResponse(networkResponse);
	            request.addMarker("network-parse-complete");
	
	            // Write to cache if applicable.
	            // TODO: Only update cache metadata instead of entire record for 304s.
	            //缓存数据
	            if (request.shouldCache() && response.cacheEntry != null) {
	                mCache.put(request.getCacheKey(), response.cacheEntry);
	                request.addMarker("network-cache-written");
	            }
	
	            // Post the response back.
	            request.markDelivered();
	            //和CacheDispatcher同一个mDelivery,mDelivery默认为ExecutorDelivery
	            mDelivery.postResponse(request, response);
	
	            request.notifyListenerResponseReceived(response);
	        } catch (VolleyError volleyError) {
	            volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
	            parseAndDeliverNetworkError(request, volleyError);
	            request.notifyListenerResponseNotUsable();
	        } catch (Exception e) {
	            VolleyLog.e(e, "Unhandled exception %s", e.toString());
	            VolleyError volleyError = new VolleyError(e);
	            volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
	            mDelivery.postError(request, volleyError);
	            request.notifyListenerResponseNotUsable();
	        } finally {
	            request.sendEvent(RequestQueue.RequestEvent.REQUEST_NETWORK_DISPATCH_FINISHED);
	        }
	    }
	}

processRequest函数从网络队列中取出请求,判断该请求是否被取消,取消的话直接中止该函数,
没有取消则发起网络请求获取响应数据,判断响应码是不是304和该请求是否已请求过,
如果两个条件都满足,中断该函数;否则解析响应数据, 接着判断是否进行缓存,
最后将缓存数据解析的结果回调给主线程

核心的点在于

  • 调用mNetwork.performRequest(request)发起网络请求
  • 调用request.parseNetworkResponse(networkResponse)解析响应的数据,这个在CacheDispatcher的工作流程已经提到过

而mNetwork不就是一开始在Volley类的newRequestQueue创建的BasicNetwork实例,接着看BasicNetwork类的performRequest函数发起网络请求的流程

5.发起网络请求的工作流程


	public class BasicNetwork implements Network {

		@Override
	    public NetworkResponse performRequest(Request<?> request) throws VolleyError {
	        long requestStart = SystemClock.elapsedRealtime();
	        while (true) {
	            HttpResponse httpResponse = null;
	            byte[] responseContents = null;
	            List<Header> responseHeaders = Collections.emptyList();
	            try {
	                // Gather headers.
	                Map<String, String> additionalRequestHeaders =
	                        getCacheHeaders(request.getCacheEntry());
	                //底层使用HttpUrlConnection或HttpClient发起网络请求
	                httpResponse = mBaseHttpStack.executeRequest(request, additionalRequestHeaders);
	                int statusCode = httpResponse.getStatusCode();
	
	                responseHeaders = httpResponse.getHeaders();
	                // Handle cache validation.
	                //响应码为304的情况
	                if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) {
	                    Entry entry = request.getCacheEntry();
	                    if (entry == null) {
	                        return new NetworkResponse(
	                                HttpURLConnection.HTTP_NOT_MODIFIED,
	                                /* data= */ null,
	                                /* notModified= */ true,
	                                SystemClock.elapsedRealtime() - requestStart,
	                                responseHeaders);
	                    }
	                    // Combine cached and response headers so the response will be complete.
	                    List<Header> combinedHeaders = combineHeaders(responseHeaders, entry);
	                    return new NetworkResponse(
	                            HttpURLConnection.HTTP_NOT_MODIFIED,
	                            entry.data,
	                            /* notModified= */ true,
	                            SystemClock.elapsedRealtime() - requestStart,
	                            combinedHeaders);
	                }
	
	                // Some responses such as 204s do not have content.  We must check.
	                InputStream inputStream = httpResponse.getContent();
	                if (inputStream != null) {
	                    responseContents =
	                            inputStreamToBytes(inputStream, httpResponse.getContentLength());
	                } else {
	                    // Add 0 byte response as a way of honestly representing a
	                    // no-content request.
	                    responseContents = new byte[0];
	                }
	
	                // if the request is slow, log it.
	                long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
	                logSlowRequests(requestLifetime, request, responseContents, statusCode);
	
	                if (statusCode < 200 || statusCode > 299) {
	                    throw new IOException();
	                }
	                return new NetworkResponse(
	                        statusCode,
	                        responseContents,
	                        /* notModified= */ false,
	                        SystemClock.elapsedRealtime() - requestStart,
	                        responseHeaders);
	            } catch (SocketTimeoutException e) {
	                attemptRetryOnException("socket", request, new TimeoutError());
	            } catch (MalformedURLException e) {
	                throw new RuntimeException("Bad URL " + request.getUrl(), e);
	            } catch (IOException e) {
	                int statusCode;
	                if (httpResponse != null) {
	                    statusCode = httpResponse.getStatusCode();
	                } else {
	                    throw new NoConnectionError(e);
	                }
	                VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
	                NetworkResponse networkResponse;
	                if (responseContents != null) {
	                    networkResponse =
	                            new NetworkResponse(
	                                    statusCode,
	                                    responseContents,
	                                    /* notModified= */ false,
	                                    SystemClock.elapsedRealtime() - requestStart,
	                                    responseHeaders);
	                    if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED
	                            || statusCode == HttpURLConnection.HTTP_FORBIDDEN) {
	                        attemptRetryOnException(
	                                "auth", request, new AuthFailureError(networkResponse));
	                    } else if (statusCode >= 400 && statusCode <= 499) {
	                        // Don't retry other client errors.
	                        throw new ClientError(networkResponse);
	                    } else if (statusCode >= 500 && statusCode <= 599) {
	                        if (request.shouldRetryServerErrors()) {
	                            attemptRetryOnException(
	                                    "server", request, new ServerError(networkResponse));
	                        } else {
	                            throw new ServerError(networkResponse);
	                        }
	                    } else {
	                        // 3xx? No reason to retry.
	                        throw new ServerError(networkResponse);
	                    }
	                } else {
	                    attemptRetryOnException("network", request, new NetworkError());
	                }
	            }
	        }
	    }
	}

上面的函数中核心的点在mBaseHttpStack.executeRequest发起网络请求,mBaseHttpStack则是在Volley类的newRequestQueue函数创建的HurlStack实例或HttpClientStack实例,HttpClientStack类主要封装了HttpClient的网络请求操作,在Android2.3版本之前才使用HttpClientStack这个类,所以这个类基本淘汰了. 而HurlStack类是对HttpURLConnection的网络请求做了封装

6. 将响应结果进行回调

在NetworkDispatcher和CacheDispatcher会将响应数据解析成功的结果,回调给主线程,这里面是怎么回调到主线程的? 可以看到回调主要是调用mDelivery.postResponse(request, response)这行代码,其中的mDelivery是从RequestQueue类传递过来的,看RequestQueue的构造函数


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

	public RequestQueue(
            Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) {
        mCache = cache;
        mNetwork = network;
        mDispatchers = new NetworkDispatcher[threadPoolSize];
        mDelivery = delivery;
    }

mDelivery就是在RequestQueue的构造函数中创建的, 其实例是ExecutorDelivery,这里注意下创建ExecutorDelivery实例传入的参数是持有主线程Looper的Handler, mDelivery是在RequestQueue类的start函数中创建CacheDispatcher和NetworkDispatcher时传递过去的,接着看ExecutorDelivery的postResponse函数做了什么?


	public class ExecutorDelivery implements ResponseDelivery {

		private final Executor mResponsePoster;

		public ExecutorDelivery(final Handler handler) {
	        // Make an Executor that just wraps the handler.
	        mResponsePoster =
	                new Executor() {
	                    @Override
	                    public void execute(Runnable command) {
	                        handler.post(command);
	                    }
	                };
	    }

		@Override
	    public void postResponse(Request<?> request, Response<?> response) {
	        postResponse(request, response, null);
	    }
	
	    @Override
	    public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
	        request.markDelivered();
	        request.addMarker("post-response");
	        mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
	    }
	}

核心在于mResponsePoster.execute()这句代码,在其构造函数中创建mResponsePoster,可以看到mResponsePoster是个实现Executor的匿名内部类, 而在上面我们看到Handler持有的Looper来源于主线程, execute函数只有handler.post(command) 这句代码,因此mResponsePoster主要是将子线程切换到主线程.

那上面既然主要是将子线程切换到主线程,是不是缺少了线程这个主角,这里的ResponseDeliveryRunnable就是我们的线程,当执行了上面的mResponsePoster.execute()这行代码,默认就启动了线程的run函数,看ResponseDeliveryRunnable的run函数.


	private static class ResponseDeliveryRunnable implements Runnable {
	
		@Override
        public void run() {
           
			if (mRequest.isCanceled()) {
                mRequest.finish("canceled-at-delivery");
                return;
            }

            // Deliver a normal response or error, depending.
            if (mResponse.isSuccess()) {
                mRequest.deliverResponse(mResponse.result);
            } else {
                mRequest.deliverError(mResponse.error);
            }

            // If this is an intermediate response, add a marker, otherwise we're done
            // and the request can be finished.
            if (mResponse.intermediate) {
                mRequest.addMarker("intermediate-response");
            } else {
                mRequest.finish("done");
            }

            // If we have been provided a post-delivery runnable, run it.
            if (mRunnable != null) {
                mRunnable.run();
            }
        }
	}

从上面可以知道,这个run函数是执行在主线程的,这也就解释了回调给我们的响应结果为什么是在主线程的,
run函数首先判断请求是否取消,取消了就直接中止该run函数,
没取消则判断响应数据是否解析成功,解析成功则调用成功的回调函数,解析失败则调用失败的回调函数,
这里的mRequest.deliverResponse则是上面提到的StringRequest类的deliverResponse函数,负责将响应数据回调到主线程

疑问出现,这里的mRunnable有什么用呢? 而响应数据又是怎么判断解析成功的?

mRunnable有什么用呢?

在上面的CacheDispatcher的工作流程中,有1个判断是该缓存是否需要更新,先看这部分的代码


	void processRequest(final Request<?> request) throws InterruptedException {

		//...省略无关代码

		mDelivery.postResponse(
                            request,
                            response,
                            new Runnable() {
                                @Override
                                public void run() {
                                    try {
                                        mNetworkQueue.put(request);
                                    } catch (InterruptedException e) {
                                        // Restore the interrupted status
                                        Thread.currentThread().interrupt();
                                    }
                                }
                            });

		//...省略无关代码
	}

可以看到调用了ExecutorDelivery的postResponse函数,并创建Runnable的匿名内部类作为参数传递,而在run函数中是将请求添加到网络请求队列中,因此ExecutorDelivery的mRunnable主要是将请求添加到网络请求队列中。 因此,需要更新缓存的情况下,CacheDispatcher是先将满足条件的缓存回调给主线程,接着开启线程将请求添加到网络请求队列中,之后的更新缓存的活就交给NetworkDispatcher咯

响应数据又是怎么判断解析成功的?

上面是调用mResponse.isSuccess()进行判断解析是否成功的,在isSuccess函数中判断error == null,也就是error变量为null,返回true则解析成功,error变量是在私有的构造函数中进行赋值的,因此唯一设置error变量的入口只能是Response类的success函数和error函数

	
	public class Response<T> {
	
		public boolean isSuccess() {
	        return error == null;
	    }

		public static <T> Response<T> success(T result, Cache.Entry cacheEntry) {
        	return new Response<>(result, cacheEntry);
    	}
		public static <T> Response<T> error(VolleyError error) {
		    return new Response<>(error);
		}

		private Response(T result, Cache.Entry cacheEntry) {
	        this.result = result;
	        this.cacheEntry = cacheEntry;
	        this.error = null;
	    }
	
	    private Response(VolleyError error) {
	        this.result = null;
	        this.cacheEntry = null;
	        this.error = error;
	    }
	}

接着看下解析的过程,看到StringRequest类的parseNetworkResponse函数


	 @Override
     protected Response<String> parseNetworkResponse(NetworkResponse response) {

        String parsed;
        try {
            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
        } catch (UnsupportedEncodingException e) {
            parsed = new String(response.data);
        }
        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
    }

在StringRequest类的parseNetworkResponse函数只有success的操作,因此如果请求是StringRequest实例,解析操作都将是成功的,接着看下请求体是json对象的情况,也就是看下JsonObjectRequest类的parseNetworkResponse函数


	public class JsonObjectRequest extends JsonRequest<JSONObject> {

		protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
	        try {
	            String jsonString =
	                    new String(
	                            response.data,
	                            HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
	            return Response.success(
	                    new JSONObject(jsonString), HttpHeaderParser.parseCacheHeaders(response));
	        } catch (UnsupportedEncodingException e) {
	            return Response.error(new ParseError(e));
	        } catch (JSONException je) {
	            return Response.error(new ParseError(je));
	        }
	    }
	}

看到这里是不是一切都了然咯,当捕获到异常的情况下,就会调用Response类的error函数,由此error值不为null。

7.场景

Volley的源码看得最深刻的就是while循环,在没有请求的情况下,不断循环的确浪费资源,还有默认开启缓存,不适合大文件流操作的情况. 但Volley也不是没有优点,简单轻巧、适合数据小的场景, 再回首下图

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值