码迷,mamicode.com
首页 > 移动开发 > 详细

Android 网络通信框架Volley的解析

时间:2015-02-06 18:57:45      阅读:387      评论:0      收藏:0      [点我收藏+]

标签:android

在2013年Google I/O大会上,Android开发团队公布了一个新的网络通信框架:Volley。它适合处理通信频繁的网络操作,但对于每一次通信的数据量则有较为苛刻的限制。本文将介绍该通信框架的用法(包括使用现成和自定义的Request),并从源码的角度探究其工作机制。

目前,Android系统中用于实现HTTP通信的方式主要有HttpURLConnection和HttpClient两个类[1],而封装了它们的框架主要有AsyncHttpClientUniversal-Image-Loader等。Volley库将HTTP通信进一步简单化,它的用法如下:

首先,由于HTTP通信势必要访问网络,我们需要在Android项目的Manifest.xml文件中添加访问网络的许可[2]:

<uses-permission android:name="android.permission.INTERNET" /> 

接下来,要先建立一个请求队列对象(RequestQueue):

RequestQueue mQueue = Volley.newRequestQueue(context);

这里的RequestQueue可以缓存所有的HTTP请求,然后按照一定的算法并发地发出这些请求(具体算法将在接下来的部分中有进一步的讲解)。由于RequestQueue能够并发处理请求,我们只需要在每一个进行网络通信的Activity中建立一个RequestQueue对象即可。

Android系统的网络通信能够处理多种媒体形式[3],而RequestQueue所能处理的具体请求也可根据数据类型分为StringRequest、JSONRequest、ImageRequest和自定义的Request等几种。接下来,本文将逐一讲解上述网络请求类的用法:

1:StringRequest

StringRequest可以向服务器端发出请求,并将数据以String的形式返回。假设我们需要创建一个请求,向百度请求其首页的网页HTML源代码,则代码如下所示:

StringRequest stringRequest = new StringRequest("http://www.baidu.com",  
                        new Response.Listener<String>() {  
                            @Override  
                            public void onResponse(String response) {  
                                 contentText.setText(response); 
                            }  
                        }, new Response.ErrorListener() {  
                            @Override  
                            public void onErrorResponse(VolleyError error) {  
                                Log.e("TAG", error.getMessage(), error);  
                            }  
                        });  

 

在这段代码中,我们创建了一个新的StringRequest对象。该对象的构造方法有三个参数,分别是目标服务器地址、响应成功时的回调和响应失败时的回调。其中目标服务器地址是百度首页;响应成功时的回调方法将contentText的内容设为该Request返回的文字内容;响应失败时的回调方法打印具体的错误信息。

在创建完StringRequest对象后,我们需要将其添加到先前创建的RequestQueue对象中,以发送该请求。这部分的代码很简单,只有一行:

mQueue.add(stringRequest); 

接下来,只需运行程序,即可在屏幕上观察到服务器端返回的数据:

  

HTTP协议定义了多种请求类型[4],通常我们关心的只有GET请求和POST请求。在以上的例子中,我们发出的是一个GET请求。而如果要发出一个POST请求,我们就需要调用另外的构造方法。在该方法中,我们可以指定请求类型为POST,并且重写Request(各种具体Request共同的父类)中的getParams()方法,在其中输入提交给服务器端的参数。代码如下所示:

StringRequest stringRequest = new StringRequest(Method.POST, url,  listener, errorListener) {  
    @Override  
    protected Map<String, String> getParams() throws AuthFailureError {  
        Map<String, String> map = new HashMap<String, String>();  
        map.put("params1", "value1");  
        map.put("params2", "value2");  
        return map;  
    }  
};          

2.JSONRequest

JSON是一种轻量级的数据交换格式它基于JavaScript的一个子集采用完全独立于语言的文本格式。这些特性使JSON成为理想的数据交换语言易于人阅读和编写,同时也易于机器解析和生成[5]而顾名思义,JsonRequest就是用于和服务器端交换JSON格式的数据的。JsonRequest有两个子类(JsonObjectRequest和JsonArrayRequest),分别用来处理单个的JSON对象和JSON的数组。

JsonObjectRequest的用法与上述的StringRequest类似,创建一个对象,在其构造方法中指定服务器URL地址和响应成功和失败时的回调,再把它加入请求队列中即可。代码如下:

       RequestQueue mRequestQueue = Volley.newRequestQueue(this);

        String url = "http://pipes.yahooapis.com/pipes/pipe.run?_id=giWz8Vc33BG6rQEQo_NLYQ&_render=json";

 

        JsonObjectRequest jr = new JsonObjectRequest(Request.Method.GET,url,null,new Response.Listener<JSONObject>() {

            @Override

            public void onResponse(JSONObject response) {

                try{

                    JSONObject valueobj = response.getJSONObject("value");

                    JSONArray jsonArray = valueobj.getJSONArray("items");

                    for(int i=0;i<jsonArray.length();i++){

                        JSONObject item = jsonArray.getJSONObject(i);

                        String description = item.getString("description");

                        adapter.add(description);

                    }

                }catch (JSONException e) {

                    throw new RuntimeException(e);

                }

 

            }

        },new Response.ErrorListener() {

            @Override

            public void onErrorResponse(VolleyError error) {

                error.printStackTrace();

            }

        });

        mRequestQueue.add(jr);       

在该例中,我们使用了一个雅虎提供的查询新闻的接口,从中获取了JSON格式的当天的新闻。获取新闻之后,我们在成功响应的回调方法中打印了返回的JSON数据,并取出了其中的一部分放在adapter中,从而实现将新闻内容显示在屏幕上的效果。

 

3.ImageRequest

ImageRequest可用于从服务器端获取图片。它作为Request的一个子类,也具有和上述Request具体类型相类似的使用方法。在创建RequestQueue之后,即可调用其构造方法。

 mImageView= (ImageView) findViewById(R.id.webImage);

        newRequestQueue = Volley.newRequestQueue(ImageRequestActivity.this);

        ImageRequest imageRequest = new ImageRequest("http://imgt6.bdstatic.com/it/u=2,887966933&fm=19&gp=0.jpg",

                new Response.Listener<Bitmap>()

                {

                    @Override

                    public void onResponse(Bitmap response)

                    {

                        mImageView.setImageBitmap(response);

                    }

                }, 0, 0, Bitmap.Config.RGB_565, null);

        newRequestQueue.add(imageRequest);

可以看到,ImageRequest的构造函数接收六个参数,这比StringRequest和JsonRequest稍多一些:

第一个参数就是图片的URL地址,这和其它的Request中的URL参数作用相同;

第二个参数是图片请求成功的回调,这里我们将服务器返回的Bitmap设置到mImageView中;

第三和第四个参数分别用于指定允许图片最大的宽度和高度;

第五个参数用于指定图片的颜色属性;

第六个参数是图片请求失败的回调,这里我们什么都不做。

最后我们同样需要将这个请求输入到请求队列中。具体代码和其它类型的Request是相同的。运行上述代码后,我们即可看到我们的app从网络上取得了如下的图片,并把它显示在mImageView的位置:

 

4.自定义Request

除上述各类型以外,Volley还支持自定义类型的Request。接下来,本文将以软件学院学生服务平台中的代码为例,说明自定义Request的用法。

在服务平台的“校园活动”页面中,用户可以看到最新的校园活动信息。为了从服务器端或获取相应信息,我们就需要使用自定义的Request。代码如下所示:

CampusEventResponse activityResponse = new CampusEventResponse(getActivity(),

                    !isLoadMore) {

                @Override

                public void onResponse(JSONObject result) {

                    super.onResponse(result);

                    Lgr.i(result.toString());

                    Message msg = mHandler.obtainMessage();

                    try {

                        msg.what = result.getInt("status");

                        if (isLoadMore) {

                            isMoreData = result.getJSONArray("body").length() == 0 ? false : true;

                        }

                    } catch (JSONException e) {

                        e.printStackTrace();

                    }

 

                    mHandler.sendMessage(msg);

                }

 

                @Override

                public Object onErrorStatus(CSTStatusInfo statusInfo) {

                    return super.onErrorStatus(statusInfo);

                }

 

                @Override

                public void onErrorResponse(VolleyError error) {

                    super.onErrorResponse(error);

                }

            };

 

            EventRequest eventRequest = new EventRequest(CSTRequest.Method.GET,

                    mEventCategory.getSubUrl(), null,

                    activityResponse).setPage(mCurrentPage).setPageSize(DEFAULT_PAGE_SIZE);

            mEngine.requestJson(eventRequest);

其中,CampusEventResponse是Response的一个派生类。在服务器端返回数据后,其中的onResponse方法将会得到执行。而本例中生成的CampusEventResponse对象,则被作为一个参数,输入EventRequest的构造方法中,起到监听器的作用。

EventRequest就是一种自定义的Request,它的代码如下所示:

public class EventRequest extends CSTJsonRequest {

 

    private String subUrl;

 

    private int page;

 

    private int pageSize;

 

    private String keywords;

 

    private boolean hasParams = false;

 

    public EventRequest(int method, String subUrl,

            Map<String, String> params,

            CSTResponse<JSONObject> response) {

        super(method, subUrl, params, response);

        this.subUrl = subUrl;

    }

 

    @Override

    public String getUrl() {

        if (hasParams) {

            StringBuilder sb = new StringBuilder();

            sb.append("?");

            try {

                if (page > 0) {

                    sb.append("page=").append(URLEncoder.encode("" + page, "UTF-8")).append("&");

                }

                if (pageSize > 0) {

                    sb.append("pageSize=").append(URLEncoder.encode("" + pageSize, "UTF-8"))

                            .append("&");

                }

                if (keywords != null) {

                    sb.append("keywords=").append(URLEncoder.encode(keywords, "UTF-8")).append("&");

                }

            } catch (UnsupportedEncodingException e) {

                e.printStackTrace();

            }

            sb.deleteCharAt(sb.length() - 1);

 

            return super.getUrl() + sb.toString();

        }

        return super.getUrl();

    }

 

    public EventRequest setPage(int page) {

        this.page = page;

        hasParams = true;

        return this;

    }

 

    public EventRequest setPageSize(int pageSize) {

        this.pageSize = pageSize;

        hasParams = true;

        return this;

    }

 

    public EventRequest setKeywords(String keywords) {

        this.keywords = keywords;

        hasParams = true;

        return this;

    }

}

我们可以看到,它继承了CSTJsonRequest类(同样是一个自定义Request类,接下来会有讲解)。EventRequest除了构造方法之外,还重写了Request类中的getURL方法。该方法可以根据Page、PageSize和keywords三个变量构造出所需的URL。此外,该类中还有相应的方法可用于设置上述三个变量。

CSTJsonRequest是EventRequest的父类,它的代码如下所示:

public class CSTJsonRequest extends CSTRequest<JSONObject> {

 

    private static final String BASE_URL = "http://www.cst.zju.edu.cn/isst";

 

    public CSTJsonRequest(int method, String subUrl, Map<String, String> params,

        CSTResponse<JSONObject> response) {

        super(method, BASE_URL + subUrl, params, response);

    }

 

    @Override

    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {

        try {

            String jsonString = new String(response.data,

                    HttpHeaderParser.parseCharset(response.headers));

            CSTHttpUtil.refreshCookies(BASE_URL, response.headers);

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

        }

    }

}

 

可以看到,该类继承了CSTRequest类,并在构造方法中调用了其父类的构造方法。

另外,它实现了parseNetworkResponse方法,用于解析从服务器端返回的JSON数据。若成功响应,则返回Response.success方法,并将解析出的包含JSON内容的String作为参数输入其中。如果解析不成功,则执行Response.error方法,并将抛出的异常对象作为参数。

综上所述,为了从服务器端请求相应数据,需要建立一个Response派生类对象,并在其onResponse中指定成功返回时执行的内容。然后将该对象作为监听器,传入自定义Request对象的构造方法中,最后将Request对象加入请求队列。其中自定义Request的父类(同样也是Request的派生类)中重写了parseNetworkResponse方法,将服务器返回的数据转化为一个String。然后Response.success方法被调用,该String被重新转化为一个JSON对象并向上传递。

4.Volley框架源码解析

 

Volley的官方文档中附有一张Volley的工作流程图,如下图所示。

技术分享

从这张工作流程图中我们可以看到:在一个请求被加入到缓存队列中以后,它将被CacheDispatcher分配到一个合适的去向。如果在cache中已经存有该请求所对应的数据,那么就通过cache线程从cache中读取数据,将其解析后返回主线程;如果在cache中未能找到相应数据,则启动network线程,将其通过NetworkDispatcher发送到网络,从服务器端取回数据,写到cache中,并将其解析后返回给主线程。接下来,本文将对Volley请求的源码作一初步分析,并在此过程中深入说明上图所示的工作机制。

在使用Volley时,如先前的例子所示,我们总是需要先建立一个RequestQueue。在上文中,我们使用的代码是

Volley.newRequestQueue(context);

该方法的代码如下所示:

public static RequestQueue newRequestQueue(Context context) {  

    return newRequestQueue(context, null);  

}  

 

可以看到:该方法内只有一行代码,它调用了newRequestQueue()并传入了context和null作为参数。而newRequestQueue()方法的源代码如下:

 

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) {  

    }  

    if (stack == null) {  

        if (Build.VERSION.SDK_INT >= 9) {  

            stack = new HurlStack();  

        } else {  

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

        }  

    }  

    Network network = new BasicNetwork(stack);  

    RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);  

    queue.start();  

    return queue;  

}  

 

可以看到,该方法所创建的stack取决于用户的系统版本:如果大于等于9,则这里会在第12行创建一个新的HurlStack;反之,则会将一个HttpClientStack对象赋给stack。接下来,在用stack作为参数创建一个Network对象(网络线程其实是调用 Network对象去实现跟网络进行沟通的)之后,就可以调用RequestQueue的构造方法了。在该方法中,cache文件和Network对象被作为参数传递进去。最后,调用RequestQueue的start()方法,即可启动该请求队列。

其中,HurlStack和HttpClientStack是网络访问的最低层实现。由于android的网络访问在2.2以前是用的阿帕奇的网络访问框架,2.2以后用的是HttpConnectUrl,volley兼容2.2以下的android版本,所以它需要针对版本来提供不同的实现。HurlStack对应的是HttpConnectUrl,而HttpClientStack对应的是阿帕奇的网络访问框架。

 

其中的Network是一个接口,这里具体的实现是BasicNetwork,它的主要功能就是利用performRequest方法处理网络通信过程中的具体细节。该方法的代码如下所示:

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;  

            Map<String, String> responseHeaders = new HashMap<String, String>();  

            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) {  

                    return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,  

                            request.getCacheEntry() == null ? null : request.getCacheEntry().data,  

                            responseHeaders, true);  

                }  

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

            } catch (Exception e) {  

                ……  

            }  

        }  

    }  

}  

其中的第14行调用了performRequest()方法,这里的HttpStack就是在一开始调用newRequestQueue()方法创建的实例,取决于系统版本,它既可能是HurlStack也可能是一个HttpClientStack。在得到数据之后服务器返回的数据会被组装成一个NetworkResponse对象并作为该方法的返回值

 

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

    }  

}  

在本方法中,上述代码创建了一个CacheDispatcher实例和若干个(默认情况下为四个)networkDispatcher实例,并调用了它们的start()方法。其中,CacheDispatcher和networkDispatcher都是Thread的子类,它们分别是用于处理缓存和网络请求的线程。

接下来,我们在构建自己的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;  

    }  

}  

  add方法有以下几个步骤:

1:判断当前的Request是否使用缓存。如不使用,则将请求加入mNetworkQueue并直接返回;如使用,则判断之前是否有执行相同的请求且还没有返回结果。

2:如果上一步最后的判断是true,将此请求加入mWaitingRequests队列,不再重复请求,在上一个请求返回时直接发送结果。

3:如果第1步最后的判断是false,将请求加入缓存队列mCacheQueue,并将其CacheKey加入mWaitingRequests中。

可见,add方法并没有执行任何实际的请求操作。实际的操作是由CacheDispatcher和NetworkDispatcher这两个类完成的。其中CacheDispatcher是Thread的子类,具体代码如下:

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 {  

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

            }  

        }  

    }  

}  

 

上述代码主要完成以下工作:

1:从mCacheQueue取出请求。

2:检查请求所对应的CacheKey在缓存中是否存在

3:如果不存在,就加到mNetworkQueue中,并继续取下一个请求。如果存在,判断是否过期。

4:如果过期,就加入网络队列mNetworkQueue中,并继续取下一个请求。如果没过期,判断是否需要刷新。

5:如果不需要刷新,直接派发结果。如果需要刷新,调用mDelivery.postResponse派发结果,并将请求加入网络队列重新请求最新数据。

 

而用于处理网络请求的NetworkDispatcher代码如下所示:

public class NetworkDispatcher extends Thread {  

    ……  

    @Override  

    public void run() {  

        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  

        Request<?> request;  

        while (true) {  

            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) {  

                parseAndDeliverNetworkError(request, volleyError);  

            } catch (Exception e) {  

                VolleyLog.e(e, "Unhandled exception %s", e.toString());  

                mDelivery.postError(request, new VolleyError(e));  

            }  

        }  

    }  

}  

NetworkDispatcher的工作原理与CacheDispatcher相似。当start方法被调用后,它将不停地从mNetworkQueue取出请求,然后通过Network接口向网络发送请求。

在取回请求结果后,如果服务器返回304,并且结果已经通过缓存派发了,那么什么也不做。否则调用Request的parseNetworkResponse方法解析请求结果,并派发结果。


Android 网络通信框架Volley的解析

标签:android

原文地址:http://6103630.blog.51cto.com/6093630/1612489

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!