Volley网络请求流程分析(以图片请求为例)

Volley已经封装了常用格式数据的请求, 例如image, json, string等;

在此对image的请求过程跟踪一下.

首先从调用处开始:

public class MainActivity extends Activity implements Listener<Bitmap>, ErrorListener{

    private ImageView mImage = null;
    private RequestQueue mQueue = null;
    private ImageRequest mImageRequest = null;
    
    private String mUrl = null;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mImage = (ImageView) findViewById(R.id.imageview);
        
        mImage.setMaxWidth(720);
        mImage.setMaxHeight(1080);
        
        mQueue = Volley.newRequestQueue(this);
        mUrl = "http://pp.myapp.com/ma_pic2/0/shot_11673554_20452929_3_1423106639/550";
        
        mImageRequest = new ImageRequest(mUrl, this, mImage.getWidth() , mImage.getHeight(), Config.ARGB_8888, this);
        
        mQueue.add(mImageRequest);
    }

    @Override
    public void onResponse(Bitmap bitmap) {
        mImage.setImageBitmap(bitmap);
    }

    @Override
    public void onErrorResponse(VolleyError error) {
        VolleyLog.setTag("MainActivity");
        VolleyLog.e("", "");
    }
    
}

主要是两步:

1. 实例化一个ImageRequest对象;

2. 添加到Volley的请求队列;


实例化ImageRequest对象时需要传入几个参数

new ImageRequest(url, listener, maxWidth, maxHeight, decodeConfig, errorListener)

第一个是图片的链接;

第二个是Response.Listener;

第三个和第四个分别时图片最大的宽和高;

第五个是图片的编码;

第六个是Response.ErrorListener;


RequestQueue的实例化:

RequestQueue mQueue = Volley.newRequestQueue(context);

在Volley类中返回一个queue对象

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

    public static RequestQueue newRequestQueue(Context context, HttpStack stack) {

        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 = new RequestQueue(network);
        queue.start();

        return queue;
    }

可以看到, 返回的RequestQueue也是volley自定义的, 在queue实例化之后马上就start了.

    public void start() {
        stop(); // Make sure any currently running dispatchers are stopped.

        // 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, mDelivery);
            mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }
    }

不断地从queue中取出请求,并分发出去.


private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
 
 public RequestQueue(Network network, int threadPoolSize,
            ResponseDelivery delivery) {
        mNetwork = network;
        mDispatchers = new NetworkDispatcher[threadPoolSize];
        mDelivery = delivery;
    }

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

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

默认的线程池大小为4


将请求添加到queue的过程如下;

    private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();

    private final PriorityBlockingQueue<Request<?>> mNetworkQueue = new PriorityBlockingQueue<Request<?>>();   

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

        mNetworkQueue.add(request);
        return request;
    }

实际上最终的请求是存放在PriorityBlockingQueue中

request.setSequence(getSequenceNumber());是给该请求分配一个优先级, 其中getSequenceNumber()就是得到一个递增的数, 也就是说, 请求是按添加顺序进行执行的,前提是同一类请求,不同类的请求的优先级是不一样的.


上面说到了,queue会不断的分发请求, 将请求添加到queue后,


            NetworkDispatcher networkDispatcher = new NetworkDispatcher(
                    mNetworkQueue, mNetwork, mDelivery);
            mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();

public class NetworkDispatcher extends Thread

启动线程,

    @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 (Exception 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");

                // Parse the response here on the worker thread.
                Response<?> response = request
                        .parseNetworkResponse(networkResponse);
                request.addMarker("network-parse-complete");

                // Post the response back.
                request.markDelivered();
                mDelivery.postResponse(request, response);
            } catch (VolleyError volleyError) {
                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime()
                        - startTimeMs);
                parseAndDeliverNetworkError(request, volleyError);
            } catch (Exception e) {
                VolleyError volleyError = new VolleyError(e);
                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime()
                        - startTimeMs);
                mDelivery.postError(request, volleyError);
            }
        }
    }
层层封装,最终实现网络请求的地方

NetworkResponse networkResponse = mNetwork.performRequest(request);

    @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>();
                httpResponse = mHttpStack.performRequest(request, headers);

                System.out.println(httpResponse.getEntity().toString());

                StatusLine statusLine = httpResponse.getStatusLine();
                int statusCode = statusLine.getStatusCode();

                responseHeaders = convertHeaders(httpResponse.getAllHeaders());

                // 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, 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);
                }
                VolleyLog.e("Unexpected response code %d for %s", statusCode,
                        request.getUrl());
                if (responseContents != null) {
                    networkResponse = new NetworkResponse(statusCode,
                            responseContents, responseHeaders,
                            SystemClock.elapsedRealtime() - requestStart);
                    if (statusCode == HttpStatus.SC_UNAUTHORIZED
                            || statusCode == HttpStatus.SC_FORBIDDEN) {
                        attemptRetryOnException("auth", request,
                                new AuthFailureError(networkResponse));
                    } else {
                        throw new ServerError(networkResponse);
                    }
                } else {
                    throw new NetworkError(networkResponse);
                }
            }
        }
    }

在这个方法里面还是对数据的请求进行了封装

httpResponse = mHttpStack.performRequest(request, headers);


    @Override
    public HttpResponse performRequest(Request<?> request,
            Map<String, String> additionalHeaders) throws IOException,
            AuthFailureError {
        HttpUriRequest httpRequest = createHttpRequest(request,
                additionalHeaders);
        addHeaders(httpRequest, additionalHeaders);
        addHeaders(httpRequest, request.getHeaders());
        onPrepareRequest(httpRequest);
        HttpParams httpParams = httpRequest.getParams();
        int timeoutMs = request.getTimeoutMs();
        // data collection and possibly different for wifi vs. 3G.
        HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
        HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
        return mClient.execute(httpRequest);
    }

 终于找到执行请求的地方, mHttpStack是从哪里来的呢?

往上找发现, 在实例化queue的时候

stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));

这一句在上面已经贴出来了的.

我是把volley的cache部分剥离了, 所以贴出来的代码可能跟volley源码有些不同, 但是网络请求部分是没有改动的.

至此,整个请求的过程已经分析完了, 其实还有很多细节值得学习, volley既然是google开源出来的, 肯定融入了很多智慧. 这顿大餐还需慢慢咀嚼!




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值