Android 网络通信框架Volley的解析

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

目前,Android系统中用于实现HTTP通信的方式主要有HttpURLConnection和HttpClient两个类[1],而封装了它们的框架主要有AsyncHttpClient和Universal-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方法解析请求结果,并派发结果。

时间: 2024-10-25 22:29:13

Android 网络通信框架Volley的解析的相关文章

【转】Android 网络通信框架Volley简介(Google IO 2013)

Volley主页 https://android.googlesource.com/platform/frameworks/volley http://www.youtube.com/watch?v=yhv8l9F44qo&feature=player_embedded 1. 什么是Volley 在这之前,我们在程序中需要和网络通信的时候,大体使用的东西莫过于AsyncTaskLoader,HttpURLConnection,AsyncTask,HTTPClient(Apache)等,今年的Go

Android 网络通信框架Volley简介(Google IO 2013)

Volley主页 https://android.googlesource.com/platform/frameworks/volley http://www.youtube.com/watch?v=yhv8l9F44qo&feature=player_embedded 1. 什么是Volley 在 这之前,我们在程序中需要和网络通信的时候,大体使用的东西莫过于 AsyncTaskLoader,HttpURLConnection,AsyncTask,HTTPClient(Apache)等,今年的

[转]Android 网络通信框架Volley简介(Google IO 2013)

Volley主页 https://android.googlesource.com/platform/frameworks/volley http://www.youtube.com/watch?v=yhv8l9F44qo&feature=player_embedded 1. 什么是Volley 在这之前,我们在程序中需要和网络通信的时候,大体使用的东西莫过于AsyncTaskLoader,HttpURLConnection,AsyncTask,HTTPClient(Apache)等,今年的Go

Android 网络通信框架Volley基本介绍

Volley主页 https://android.googlesource.com/platform/frameworks/volley http://www.youtube.com/watch?v=yhv8l9F44qo&feature=player_embedded 1. 什么是Volley Google I/O 2013上.Volley公布了volley.在这之前,我们在程序中须要和网络通信的时候,大体使用的东西莫过于 AsyncTaskLoader HttpURLConnection A

Android 网络通信框架Volley简介

Volley主页 https://android.googlesource.com/platform/frameworks/volley http://www.youtube.com/watch?v=yhv8l9F44qo&feature=player_embedded 1. 什么是Volley Google I/O 2013上,Volley发布了volley.在这之前,我们在程序中需要和网络通信的时候,大体使用的东西莫过于 AsyncTaskLoader HttpURLConnection A

ym—— Android网络框架Volley(体验篇)

<a target=_blank href="https://android.googlesource.com/platform/frameworks/volley" style="font-family: Arial, Helvetica, sans-serif; box-sizing: border-box; background-image: initial; background-attachment: initial; background-color: rg

Android网络框架Volley

Volley是Google I/O 2013推出的网络通信库,在volley推出之前我们一般会选择比较成熟的第三方网络通信库,如: android-async-http retrofit okhttp 他们各有优劣,之前个人则比较喜欢用Android-async-http, 如今Google推出了官方的针对Android平台上的网络通信库,能使网络通信更快,更简单,更健壮,Volley在提供了高性能网络通讯功能的同时,对网络图片加载也提供了良好的支持,完全可以满足简单REST客户端的需求, 我们

Android网络框架-Volley实践 使用Volley打造自己定义ListView

这篇文章翻译自Ravi Tamada博客中的Android Custom ListView with Image and Text using Volley 终于效果 这个ListView呈现了一些影视信息,每一行是一个影片的信息,每一行中有一张电影的图片,电影的名字.评分.类型.年份等信息. 1.json数据 我们通过解析json然后拿到数据,这个json数据包含json数组.每一个json数组中是一个json对象,json对象中包含了电影的图片url地址.标题.年份.评分.类型等信息 JSO

ym—— Android网络框架Volley(实战篇)

转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103).谢谢支持. 之前讲了ym-- Android网络框架Volley(体验篇),大家应该了解了volley的使用,接下来我们要看看怎样把volley使用到实战项目里面,我们先考虑下一些问题: 从上一篇来看 mQueue 仅仅须要一个对象就可以,new RequestQueue对象对资源一种浪费,我们应该在application.以及能够把取消请求的方法也在application进行统一管理,看下面代