android-----Volley框架源码分析

作为Google的亲儿子,Volley框架从诞生之日起就受到极大推崇,他简单且适用于异步环境下的频繁网络操作,但是对于上传文件或者想要post一些较大数据的场合,显然他是束手无策的,这篇博文我会从源码角度带大家看看Volley框架到底是怎么个执行流程;

平常我们使用Volley的标准步骤是:

(1)创建一个RequestQueue队列;

(2)创建一个Request对象(当然实际中可能就是Request的子类了,比如:StringRequest、JsonRequest等等);

(3)调用RequestQueue的add方法将Request对象添加到请求队列中;

那么很自然,源码分析应该是从创建RequestQueue队列开始的,创建RequestQueue的语句是Volley.newRequestQueue(context)

 public static RequestQueue newRequestQueue(Context context) {
        return newRequestQueue(context, null);
    }

	public static RequestQueue newRequestQueue(Context context, HttpStack stack)
    {
    	return newRequestQueue(context, stack, -1);
    }

	public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
        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) {
        }

        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;
        if (maxDiskCacheBytes <= -1)
        {
        	// No maximum size specified
        	queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
        }
        else
        {
        	// Disk cache size specified
        	queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
        }

        queue.start();

        return queue;
    }

newRequestQueue有四个构造函数,但是他们最后都会执行到newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes)这个构造函数上面,我只列出了用到的3个,newRequestQueue(context)首先会调用newRequestQueue(context,null),接着调用newRequestQueue(context,null,-1),程序走到第21行时,判断stack是否等于null,等于的话则进入if语句块,如果SDK版本号大于9的话,则创建HurlStack对象,否则的话创建HttpClientStack对象,接着在第31行创建一个参数为stack的Network对象,在第34行判断maxDiskCacheBytes是否小于等于-1,这里我们传入的参数是-1,则进入if语句块,利用刚刚生成的network对象创建RequestQueue对象,我们来看看RequestQueue的构造函数:

public RequestQueue(Cache cache, Network network) {
        this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
    }

    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;
    }

可以看到调用RequestQueue(Cache cache, Network network)实际上最后都会调用到有四个参数的构造函数上,其中DEFAULT_NETWORK_THREAD_POOL_SIZE的值为4,表示网络请求缓存池的大小是4;

    private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;

回到newRequestQueue函数,在创建出RequestQueue队列之后,第45行启动了我们的请求队列,很自然我们需要到RequestQueue里面的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();
        }
    }

首先执行stop方法暂停当前的缓存线程和网络请求线程:

 public void stop() {
        if (mCacheDispatcher != null) {
            mCacheDispatcher.quit();
        }
        for (int i = 0; i < mDispatchers.length; i++) {
            if (mDispatchers[i] != null) {
                mDispatchers[i].quit();
            }
        }
    }

默认情况下的缓存线程只有一个,网络请求线程有4个;

接着start方法的第4行重新创建一个缓存线程,并且启动该线程,第8行通过for循环默认创建4个网络请求线程,并且启动每个线程,注意CacheDispatcher和NetworkDispatcher是继承自Thread的,所以本质上他们还是线程:

public class CacheDispatcher extends Thread {
public class NetworkDispatcher extends Thread {

这也就解释了在你使用Volley创建RequestQueue队列之后,同时会看到还有另外5个线程的原因了;

接着我们便去创建自己的Request对象,随后调用add方法将当前的Request对象添加到了RequestQueue队列中,那么,add方法到底做了些什么事呢?

public <T> Request<T> add(Request<T> request) {
        // Tag the request as belonging to this queue and add it to the set of current requests.
        request.setRequestQueue(this);
        synchronized (mCurrentRequests) {
            mCurrentRequests.add(request);
        }

        // Process requests in the order they are added.
        request.setSequence(getSequenceNumber());
        request.addMarker("add-to-queue");

        // If the request is uncacheable, skip the cache queue and go straight to the network.
        if (!request.shouldCache()) {
            mNetworkQueue.add(request);
            return request;
        }

        // Insert request into stage if there's already a request with the same cache key in flight.
        synchronized (mWaitingRequests) {
            String cacheKey = request.getCacheKey();
            if (mWaitingRequests.containsKey(cacheKey)) {
                // There is already a request in flight. Queue up.
                Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
                if (stagedRequests == null) {
                    stagedRequests = new LinkedList<Request<?>>();
                }
                stagedRequests.add(request);
                mWaitingRequests.put(cacheKey, stagedRequests);
                if (VolleyLog.DEBUG) {
                    VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
                }
            } else {
                // Insert 'null' queue for this cacheKey, indicating there is now a request in
                // flight.
                mWaitingRequests.put(cacheKey, null);
                mCacheQueue.add(request);
            }
            return request;
        }
    }

第3--10行设置一些Request请求的参数,接着第13行判断当前请求是否可以被缓存,如果不可以的话会将当前请求加入到网络请求队列中同时直接返回request结束add方法,可以缓存的话(默认情况下是可以缓存的,因为在Request类中存在这么一句代码:private boolean mShouldCache = true;),则会跳过if语句去执行synchronized语句块,首先会到第21行查看在mWaitingRequests中是否存在cacheKey对应的对象,mWaitingRequests是一个Map对象,而cacheKey的值是通过getCacheKey得到的,实际上就是一个url,具体值到底是什么可以在Request.java类中看到如下源码:

   public String getCacheKey() {
        return getUrl();
    }
<pre name="code" class="java">   /** The redirect url to use for 3xx http responses */
    private String mRedirectUrl;
   /** URL of this request. */
    private final String mUrl;
   public String getUrl() { return (mRedirectUrl != null) ? mRedirectUrl : mUrl; }

getCacheKey会调用getUrl,而getUrl返回的值就是重定向或者我们本身所请求的url了,接着分析add方法,如果mWaitingRequests中存在cacheKey的话,则首先会在23行获得该cacheKey所对应的value(这个值是一个Queue队列)值,接着在第27行将当前的Request请求添加到刚刚获得的队列中,随后28行更新mWaitingRequests中对应于cacheKey的value值;如果mWaitingRequests中不存在cacheKey的话,则在36行将当前Request请求添加到缓存队列中;

我们发现上面的add操作不是把当前请求添加到网络请求队列中就是将其添加到缓存队列中,两个队列中的请求真正的执行者就是我们之前创建的那5个线程了,因为他们都是线程,所以执行的代码必定出现在各自的run方法中,首先来看看缓存线程的run方法,它位于CacheDispatcher.java类中:

   @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 {
                // Get a request from the cache triage queue, blocking until
                // at least one is available.
                final Request<?> request = mCacheQueue.take();
                request.addMarker("cache-queue-take");

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

                // 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.
                    mNetworkQueue.put(request);
                    continue;
                }

                // If it is completely expired, just send it to the network.
                if (entry.isExpired()) {
                    request.addMarker("cache-hit-expired");
                    request.setCacheEntry(entry);
                    mNetworkQueue.put(request);
                    continue;
                }

                // 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");

                if (!entry.refreshNeeded()) {
                    // Completely unexpired cache hit. Just deliver the response.
                    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;

                    // 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) {
                                // Not much we can do about this.
                            }
                        }
                    });
                }

            } catch (InterruptedException e) {
                // We may have been interrupted because it was time to quit.
                if (mQuit) {
                    return;
                }
                continue;
            }
        }
    }

可以看到此run方法第9行是while(true)死循环,说明这个线程会一直在后台执行的,第13行首先会从缓存队列中取出请求,接着在第23行获取当前Request对应的缓存中的内容,第24行进行判断,如果不存在的话进入if语句块,将当前请求添加到网络请求队列中,并且跳出此次循环;如果当前缓存中存在与当前Request对应的缓存内容的话,接着在32行判断该缓存内容是否已经过期,如果已经过期的话,则执行if语句块,将当前请求添加到网络请求队列中,同时也跳出本次循环的剩余内容;如果当前Request对应的缓存内容即存在也没过期的话,就会执行后面的内容,在第41行会调用Request的parseNetworkResponse方法
:

 abstract protected Response<T> parseNetworkResponse(NetworkResponse response);

可以看到,这只是一个抽象方法,具体需要子类去实现,比如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));
    }

回到CacheDispatcher的run方法第45行会查看当前的cache缓存内容如果是没有过期的话,直接调用mDelivery的postResponse将response结果发送出去,mDelivery是ResponseDelivery类型的,他是一个接口,我们找到他的一个实现类ExecutorDelivery,它里面的postResponse方法如下:

@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方法传入了一个ResponseDeliveryRunnable类型的对象,他是ExecutorDelivery的私有内部类,继承自Runnable:

    private class ResponseDeliveryRunnable implements Runnable {

调用mResponsePoster的execute方法其实就是调用ResponseDeliveryRunnable的run方法,来看看它里面做了些什么事:

public void run() {
            // If this request has canceled, finish it and don't deliver.
            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();
            }
       }

第9行会判断请求是否成功,成功的话会调用Request的deliverResponse方法,失败的话调用Request的deliverError方法:

 abstract protected void deliverResponse(T response);

可以看到Request的deliverResponse是个抽象方法,需要我们在子类中实现,比如:StringRequest中的实现是:

 @Override
    protected void deliverResponse(String response) {
        mListener.onResponse(response);
    }

他会回调Listener的onResponse方法,而这个方法就是我们在平常返回结果执行成功后需要自己实现的方法了;

而Request的deliverError就是一个具体方法了:

public void deliverError(VolleyError error) {
        if (mErrorListener != null) {
            mErrorListener.onErrorResponse(error);
        }
    }

他会调用ErrorListener的onErrorResponse方法,这也就是我们平常返回结果执行失败后需要回调的方法,onErrorResponse里面的代码需要我们自己实现;

这样的话,缓存队列中的线程执行过程已经分析完毕了,接下来就是网络请求队列中的线程执行流程了,其实想想也知道,两者肯定有共同的地方,只不过缓存线程的话,因为已经存在返回的结果了,所以我们只需要将该结果进行适当的解析并且返回给主线程就可以了,网络请求线程的话就需要我们首先先去网络中获取到结果随后才能进行适当的解析并且返回给主线程,好的,接下来从源码角度看看Volley是怎么实现的:

查看NetworkDispatcher的run方法源码如下:

 @Override
    public void run() {
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        while (true) {
            long startTimeMs = SystemClock.elapsedRealtime();
            Request<?> request;
            try {
                // Take a request from the queue.
                request = mQueue.take();
            } catch (InterruptedException e) {
                // We may have been interrupted because it was time to quit.
                if (mQuit) {
                    return;
                }
                continue;
            }

            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");
                    continue;
                }

                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.
                if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                    request.finish("not-modified");
                    continue;
                }

                // 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();
                mDelivery.postResponse(request, response);
            } catch (VolleyError volleyError) {
                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                parseAndDeliverNetworkError(request, volleyError);
            } 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);
            }
        }
    }

首先看到第4行和CacheDispatcher一样,同样也是一个while(true)的死循环,表明网络请求线程也是会在后台一直查看网络请求队列中是否有需要执行的请求的,第9行从网络请求队列中取出队头元素,接着第23行判断请求是否被暂停,被暂停的话则结束本次循环,没有的话执行到31行,通过Network的performRequest方法执行request请求,而Network只是一个接口,我们找到他的一个实现类BasicNetwork来看看它里面performRequest这个方法的源码:

@Override
    public NetworkResponse performRequest(Request<?> request) throws VolleyError {
        long requestStart = SystemClock.elapsedRealtime();
        while (true) {
            HttpResponse httpResponse = null;
            byte[] responseContents = null;
            Map<String, String> responseHeaders = Collections.emptyMap();
            try {
                // Gather headers.
                Map<String, String> headers = new HashMap<String, String>();
                addCacheHeaders(headers, request.getCacheEntry());
                httpResponse = mHttpStack.performRequest(request, headers);
                StatusLine statusLine = httpResponse.getStatusLine();
                int statusCode = statusLine.getStatusCode();

                responseHeaders = convertHeaders(httpResponse.getAllHeaders());
                // Handle cache validation.
                if (statusCode == HttpStatus.SC_NOT_MODIFIED) {

                    Entry entry = request.getCacheEntry();
                    if (entry == null) {
                        return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null,
                                responseHeaders, true,
                                SystemClock.elapsedRealtime() - requestStart);
                    }

                    // A HTTP 304 response does not have all header fields. We
                    // have to use the header fields from the cache entry plus
                    // the new ones from the response.
                    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
                    entry.responseHeaders.putAll(responseHeaders);
                    return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,
                            entry.responseHeaders, true,
                            SystemClock.elapsedRealtime() - requestStart);
                }

                // Handle moved resources
                if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
                	String newUrl = responseHeaders.get("Location");
                	request.setRedirectUrl(newUrl);
                }

                // Some responses such as 204s do not have content.  We must check.
                if (httpResponse.getEntity() != null) {
                  responseContents = entityToBytes(httpResponse.getEntity());
                } 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, statusLine);

                if (statusCode < 200 || statusCode > 299) {
                    throw new IOException();
                }
                return new NetworkResponse(statusCode, responseContents, responseHeaders, false,
                        SystemClock.elapsedRealtime() - requestStart);
            } catch (SocketTimeoutException e) {
                attemptRetryOnException("socket", request, new TimeoutError());
            } catch (ConnectTimeoutException e) {
                attemptRetryOnException("connection", request, new TimeoutError());
            } catch (MalformedURLException e) {
                throw new RuntimeException("Bad URL " + request.getUrl(), e);
            } catch (IOException e) {
                int statusCode = 0;
                NetworkResponse networkResponse = null;
                if (httpResponse != null) {
                    statusCode = httpResponse.getStatusLine().getStatusCode();
                } else {
                    throw new NoConnectionError(e);
                }
                if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||
                		statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
                	VolleyLog.e("Request at %s has been redirected to %s", request.getOriginUrl(), request.getUrl());
                } else {
                	VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
                }
                if (responseContents != null) {
                    networkResponse = new NetworkResponse(statusCode, responseContents,
                            responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
                    if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
                            statusCode == HttpStatus.SC_FORBIDDEN) {
                        attemptRetryOnException("auth",
                                request, new AuthFailureError(networkResponse));
                    } else if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||
                    			statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
                        attemptRetryOnException("redirect",
                                request, new AuthFailureError(networkResponse));
                    } else {
                        // TODO: Only throw ServerError for 5xx status codes.
                        throw new ServerError(networkResponse);
                    }
                } else {
                    throw new NetworkError(networkResponse);
                }
            }
        }
    }

这个方法相对来说比较长,我们只挑重点来进行分析,首先第12行之前的部分都是在对我们的请求进行一些初始化的操作,第12行调用HttpStack的performRequest方法,并且将返回结果传给了HttpResponse对象,这里的HttpStack就是我们刚开始在newRequestQueue中创建的HttpStack对象,如果SDK版本号大于9的话,创建的是HurlStack对象,否则的话创建的是HttpClientStack对象,HurlStack内部是使用HttpURLConnection来进行网络请求的,HttpClientStack内部是使用HttpClient进行网络请求的,之后会将HttpResponse对象封装成NetworkResponse对象返回;

回到我们NetworkDispatcher的run方法的第31行,此时获取到了NetworkResponse对象,第47行我们判断当前Request对象是否允许缓存并且Response对象的结果是否为null,满足条件之后进入if语句块中,将当前的response返回结果添加到缓存中,接下来的过程就和上面CacheDispatcher一样了,首先对NetworkResponse进行解析,随后在第54行通过ExecutorDelivery对象调用postResponse或者在第62行通过ExecutorDelivery对象调用postError将其结果返回给主线程,这点之前上面已经讲过啦!

上面我们大体上分析了Volley框架的源码,在此做一个小结:

(1)在Volley中存在三种类型的线程:主线程、缓存线程(1个)、网络请求线程(默认4个)

(2)在Volly存在两个队列:缓存队列(缓存线程利用死循环从中取出Request请求执行)、网络请求队列(网络请求线程利用死循环从中取出Request请求执行)

(3)我们在主线程中调用newRequestQueue方法时,同时会发现启动了另外5个线程;

(4)在主线程中调用RequestQueue的add方法添加一条网络请求之后,该请求默认情况下是会被加入到缓存队列中的,如果在缓存中找到了对应于该请求的缓存结果,则会对其直接进行解析返回,之后调用ExecutorDelivery的postResponse或者postError方法将返回结果传递给主线程,这两个方法会调用Request的deliverResponse和deliverError方法,而这两个方法最终就会分别调用Listener的onResponse方法和ErrorListener的onErrorResponse方法,这也就是我们通常在使用Volley框架的时候需要自己实现的方法了;如果缓存中不存在对应Request的缓存结果或者对应于Request的缓存结果已经过期的话,则会将其添加到网络请求队列中,发送HTTP请求获取响应结果,并对响应结果进行封装、解析、写入缓存,之后呢,再采用和之前一样的方法回调回主线程;

水平有限,希望大家指正,蟹蟹啦!

时间: 2024-11-09 09:45:15

android-----Volley框架源码分析的相关文章

android 网络框架 源码分析

android 网络框架 源码分析 导语: 最近想开发一个协议分析工具,来监控android app 所有的网络操作行为, 由于android 开发分为Java层,和Native层, 对于Native层我们只要对linux下所有网络I/O接口进行拦截即可,对于java 层,笔者对android 网络框架不是很了解,所以这个工具开发之前,笔者需要对android 的网络框架进行一个简单的分析. 分析结论: 1. android 的网络框架都是基于Socket类实现的 2. java 层Socket

Android之Volley框架源码分析

临近毕业,各种事情各种忙.我也没有认真专注写过博客,最近仔细看了Volley框架的使用及其源码,思前想后,想挑战一下自己,还是写一篇博客来分享,如有错误,欢迎吐槽. Volley简介 网络请求是一个App很重要的一部分,android系统只是提供了一个平台,而android应用则是基于这个平台上进行展示数据,起到与用户进行交互的作用,数据来源于服务端,而二者之间必须通过互联网进行传输数据,在Android系统发布初期,很多开发者都是在Apache协会的Http协议的基础上进行网络请求方法的封装,

Android网络框架源码分析一---Volley

转载自 http://www.jianshu.com/p/9e17727f31a1?utm_campaign=maleskine&utm_content=note&utm_medium=mobile_author_hots&utm_source=recommendation 公司最近新起了一个项目,对喜欢尝鲜的我们来说,好处就是我们可以在真实的项目中想尝试一些新技术,验证想法.新项目对网络框架的选取,我们存在三种方案: 1.和我们之前的项目一样,使用Loader + HttpCli

(干货) Android Volley框架源码详细解析

前言 经常接触Android网络编程的我们,对于Volley肯定不陌生,但我们不禁要问,对于Volley我们真的很了解吗?Volley的内部是怎样实现的?为什么几行代码就能快速搭建好一个网络请求?我们不但要知其然,也要知其所以然,抱着这样的目的,本文主要详细讲述Volley的源码,对内部流程进行详细解析. Part 1.从RequestQueue说起 (1)还记得搭建请求的第一步是什么吗?是新建一个请求队列,比如说这样: RequestQueue queue = Volley.newReques

Volley框架源码分析

Volley框架分析Github链接 Volley框架分析 Volley源码解析 为了学习Volley的网络框架,我在AS中将Volley代码重新撸了一遍,感觉这种照抄代码也是一种挺好的学习方式.再分析Volley源码之前,我们先考虑一下,如果我们自己要设计一个网络请求框架,需要实现哪些事情,有哪些注意事项? 我的总结如下: 需要抽象出request请求类(包括url, params, method等),抽象出request请求类之后,我们可以对其继承从而实现丰富的扩展功能. 需要抽象出resp

Android网络通信Volley框架源码浅析(三)

尊重原创 http://write.blog.csdn.net/postedit/26002961 通过前面浅析(一)和浅析(二)的分析,相信大家对于Volley有了初步的认识,但是如果想更深入的理解,还需要靠大家多多看源码. 这篇文章中我们主要来研究一下使用Volley框架请求大量图片的原理,在Android的应用中,通过http请求获取的数据主要有三类: 1.json 2.xml 3.Image 其中json和xml的获取其实原理很简单,使用Volley获取感觉有点大财小用了,了解Volle

Android Small插件化框架源码分析

Android Small插件化框架源码分析 目录 概述 Small如何使用 插件加载流程 待改进的地方 一.概述 Small是一个写得非常简洁的插件化框架,工程源码位置:https://github.com/wequick/Small 插件化的方案,说到底要解决的核心问题只有三个: 1.1 插件类的加载 这个问题的解决和其它插件化框架的解决方法差不多.Android的类是由DexClassLoader加载的,通过反射可以将插件包动态加载进去.Small的gradle插件生成的是.so包,在初始

Volley框架源码浅析(一)

尊重原创http://blog.csdn.net/yuanzeyao/article/details/25837897 从今天开始,我打算为大家呈现关于Volley框架的源码分析的文章,Volley框架是Google在2013年发布的,主要用于实现频繁而且粒度比较细小的Http请求,在此之前Android中进行Http请求通常是使用HttpUrlConnection和HttpClient进行,但是使用起来非常麻烦,而且效率比较地下,我想谷歌正式基于此种原因发布了Volley框架,其实出了Voll

Volley框架源码浅析(二)

尊重原创 http://write.blog.csdn.net/postedit/25921795 在前面的一片文章Volley框架浅析(一)中我们知道在RequestQueue这个类中,有两个队列:本地队列和网络队列 /** The cache triage queue. */ private final PriorityBlockingQueue<Request<?>> mCacheQueue = new PriorityBlockingQueue<Request<

Android 开源项目源码分析第一期正式发布

由 Trinea 发起.几十名 Android 开发者参与的Android 开源项目源码分析第一期正式发布. 从简介.总体设计.流程图.详细设计全方面分析开源库源码,第一期包括 10 个著名开源库及 5 个公共技术点的全面介绍. 分析文档 作者 Volley 源码解析 grumoon Universal Image Loader 源码分析 huxian99 Dagger 源码解析 扔物线 EventBus 源码解析 Trinea xUtils 源码解析 Caij ViewPagerindicat