使用Volley传输网络数据(Transmitting Network Data Using Volley)
Volley 是一个 HTTP 库,它使得在Android应用程序中操作网络更容易,是重要的,更多快速的。Volley 属于“开放源代码项目”。.
Volley 提供了下列好处:
- 自动化的网络请求调度安排。
- 多并发的网络连接。
- 对标准HTTP 透明化的硬盘和内存 响应缓存。 cache coherence.
- 支持请求的优先级。
- 支持终止请求的 API. 你可以终止一个单独的请求,或者终止一些范围内的,或者一定请求周期段的请求。
- 轻松的定制化,比如重试和回退。
- 强顺序,它使得在网络操作时,更容易的正确处理UI和提取数据的异步。
- 调试和跟踪工具。.
Volley擅长的RPC类型(远程过程调用)的操作过去常常应用于填充UI,例如提取一页的搜索结果作为结构化数据。它更容易和其他协议整合,和出色的支持原始字符串,图片和JSON。它为你想要的特性提供内建的支持,Volley 将你从样板的代码中解放处理,使得你将注意力集中在你的业务细节。
Volley 不适合用于 大文件的下载 或者流操作,因为Volley在解析过程中会持有所有的响应内容在内存中。如果要大文件下载操作,考虑是使用其他替代,比如DownloadManager
。
核心的Volley包开放在AOSP工程下的 frameworks/volley,并且包含了主要的请求调度通道,类似于公共应用事业,在Volley "toolbox."是有效的。最简单的添加Volley到你的项目中的方式是 克隆Volley仓库并且做为你项目中的library项目
:
- 使用Git克隆Volley仓库,在你的命令提示行下输入下面的内容:
git clone https://android.googlesource.com/platform/frameworks/volley
- 导入下载的源代码到你的项目中,并且作为你的library项目 (如果你使用 Eclipse,更多描述请阅读 Managing Projects from Eclipse with ADT,) 或者编译成一个
.jar
文件.
课程
- 发送一个简单请求 (Sending a Simple Request)
- 学习如何使用Volley的默认行为发送简单请求,和如何去终止一个请求。
- 设置请求队列(Setting Up a RequestQueue)
- 学习如何设置一个请求队列,和如何使用一个单例模式来创建一个和你的App的生命周期一致的请求队列 .
- 构造一个标准请求(Making a Standard Request)
- 学习如何使用Volley的out-of-the-box请求类型(比如原始字符串,图片,JSON)发送一个请求。
- 实现自定义的请求(Implementing a Custom Request)
- 学习如何实现自定义请求。
发送一个简单请求(Sending a Simple Request)
在一个较高的水平,你使用Volley创建一个请求队列并且传入一个 请求对象 作为参数。请求队列负责管理工作线程来 启动网络操作,读取和写入到缓存,和解析响应。请求执行解析原始响应,Volley小心的分发解析的响应传送到主线程。
这节课描述了如何使用Volley.newRequestQueue
这个便利的方法来发送一个请求。它为你配置了一个请求队列。你可以通过学习下一课,“设置一个请求队列( Setting Up a RequestQueue)”的内容掌握如何配置请求队列。
这节课也描述了如何添加一个请求到消息队列,和终止一个请求。
添加网络访问权限(Add the INTERNET Permission)
要使用 Volley, 你必须在你的manifest文件中添加 android.permission.INTERNET
权限. 没有这个,你的app将不能访问网络。
使用 newRequestQueue
Volley 提供了一个便利的方法 Volley.newRequestQueue
配置一个消息队列,使用默认值,和启动队列,例如:
final TextView mTextView = (TextView) findViewById(R.id.text);
... // Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(this);
String url ="http://www.google.com"; // Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener() {
@Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
mTextView.setText("Response is: "+ response.substring(0,500));
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
mTextView.setText("That didn't work!");
}
});
// Add the request to the RequestQueue.
queue.add(stringRequest);
Volley 总是传递那些解析后的响应到主线程。运行在主线程的好处是非常便利的使用收到的数据去通知UI控件,就像 你可以在你的响应handler里*的直接修改UI控件,但是类库提供的语义格外的重要,尤其是关联到取消请求时。
阅读 Setting Up a RequestQueue 章节可以获得更多 设置请求队列的内容,它可以用来替代Volley.newRequestQueue便利的方法。
发送一个请求(Send a Request)
要发送一个请求,你可以简单的构造一个请求,并使用add() 方法添加到请求队列,像上面描述的那样.一旦你添加了请求,它被通过管道移动,获得服务,和获得原始响应和传递。
当你调用了add() 方法,Volley启动一个缓存处理线程和一个网络分发线程池。当你添加请求到队列中,它被缓存线程获拾取和分类: 如果请求可以从缓存中服务,缓存中的原始响应内容被在缓存进程中解析,并且解析后的响应内容被传递到主线程。如果请求无法从缓存中服务,它将被放置在网络队列中。第一个活动的网络线程从队里中拿到它,处理HTTP传输,在工作线程中解析响应的内容,写入响应内容到缓存,并且发送解析后的响应传递到主线程中。
注意哪些 昂贵的操作,比如阻塞I/O,和解析/解码,都是在工作线程中完成的。你可以在任何线程中添加请求,但是响应总是被传递到主线程中。
图表 1 插图说明一个请求的生命周期:
图 1. 请求的生命周期.
中断一个请求(Cancel a Request)
要中断一个请求, 在你的请求对象上 调用 cancel()方法
.一旦被中断后,Volley会确保 你的响应处理器 绝对不被调用。实际意义是你可在你的activity中的onStop()方法中中断你的等待中的请求,而且你不会*乱丢你的请求处理器,比如检查getActivity() == null ,onSaveInstanceState()
方法是否已经被调用,或者其他自卫性的样板代码。
要获得这样行为的好处,典型情况下你不得不追踪所有 “飞行中的(in-flight)”请求,以使得在合适的时机去终止它。这有一个更简单的方法: 你可以为每一个请求关联一个 标签对象。你可以使用这个标签来提供可被中断请求的范围。比如,你可以使用 Activity对象 标记你所有的请求,并且在 onStop() 时调用 requestQueue.cancelAll(this) 。同样的,你可以 在一个ViewPager选项卡中,使用他们各自的 选项卡对象 标记 它们自己的所有的 缩略图 请求,并在切换时触发终止操作,以确保 新的选项卡对象不会被 其他选项卡的请求 所持有。
下面是一个使用 字符串值作为标签 的示例:
- 定义你的标签并且添加到你的请求上。
public static final String TAG = "MyTag";
StringRequest stringRequest; // Assume this exists.
RequestQueue mRequestQueue; // Assume this exists. // Set the tag on the request.
stringRequest.setTag(TAG); // Add the request to the RequestQueue.
mRequestQueue.add(stringRequest); - 在你的 activity的
onStop()
方法中, 终止所有标记过这个标签的请求。@Override
protected void onStop () {
super.onStop();
if (mRequestQueue != null) {
mRequestQueue.cancelAll(TAG);
}
}
当调用终止请求时要非常小心。如果你 依赖 你的响应处理器,以变动一个状态或者踢开一些步骤,你需要记得这些。再次强调,在终止后相应处理绝不会被调用。
设置一个请求队列(Setting Up a RequestQueue)
上节课展示了如何使用 Volley.newRequestQueue 这个便利的方法来设置一个请求队列,以获得Volley提供的默认行为的好处。这节课教你通过明确的几个步骤来创建一个请求队列,使得你可以定制它。
这节课也描述一个推荐的实践方式,使用单例模式创建一个请求队列,这个请求队列会持续整个App的生命周期。
设置一个网络和缓存(Set Up a Network and Cache)
一个请求队列要完成它自己的工作需要两样东西: 一个 network(网络) 对象处理请求的传输,和一个 cache(缓存)对象来处理缓存。在Volley 工具盒 中已经有了里那两个标准的可用的实现: DiskBasedCache提供了一个 “每响应单文件(one-file-per-response)” 的缓存并在内存中建立索引; BasicNetwork对象提供了以 你自己选择的AndroidHttpClient
或 HttpURLConnection 对象 为基础的网络传输。
BasicNetwork 是Volley的默认 network(网络) 实现。一个 BasicNetwork 对象必须先被 使用HTTP客户端 来初始化后才能连接网络。比较有代表性的是AndroidHttpClient
or HttpURLConnection
:
- 在Android API level 9 (Gingerbread)以下的应用中,使用
AndroidHttpClient
。早于 Gingerbread,HttpURLConnection
是不可靠的. 更多请阅读 Android's HTTP Clients. - 在Android API level 9 (Gingerbread)及更高版本,使用
HttpURLConnection
.
要创建一个可运行在Android全版本的应用,你可用检查Android硬件设备上运行的Android系统的版本号,以做出选择是HTTP 客户端,比如:
HttpStack stack;
...
// If the device is running a version >= Gingerbread...
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
// ...use HttpURLConnection for stack.
} else {
// ...use AndroidHttpClient for stack.
}
Network network = new BasicNetwork(stack);
这个代码片段展示了设置请求队列的步骤:
RequestQueue mRequestQueue; // Instantiate the cache
Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap // Set up the network to use HttpURLConnection as the HTTP client.
Network network = new BasicNetwork(new HurlStack()); // Instantiate the RequestQueue with the cache and network.
mRequestQueue = new RequestQueue(cache, network); // Start the queue
mRequestQueue.start(); String url ="http://www.myurl.com"; // Formulate the request and handle the response.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// Do something with the response
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// Handle error
}
}); // Add the request to the RequestQueue.
mRequestQueue.add(stringRequest);
...
如果你仅仅需要构建单次的请求,并且不想离开线程池的范围,你可用创建在任何地方创建请求队列,和在收到响应或者错误后调用stop()方法,使用Volley.newRequestQueue()的方法可参阅 Sending a Simple Request。但是更多一般的使用情形是 使用单例模式创建请求队列并且让它和你的应用的生命周期一致,更多描述在下一章节。
使用单例模式(Use a Singleton Pattern)
如果你的应用需要经常访问网络,那么配置一个单例模式的请求队列并保持在app的整个生命周期的方式是非常有效率的。你可以有多种方式这样实现。推荐的方式是实现一个单例类来封装请求队列和其他的Volley功能方法/函数。其他的实现方式比如实现 Applicaton的子类并在Application.onCreate()方法中配置请求队列,这样的方式现在是被劝阻的;一个静态的单例能够以模块化的方式提供同样的功能。
一个关键概念是请求队列必须使用Application的context对象来初始化,而不时 Activity的context.这样确保请求队列会持续在整个app的生命周期,而在activity的context的实现会在activity被重新创建时被创建多次(比如,当用户旋转了屏幕就会重新创建activity)。
下面是一个实现了单例模式的类的示例,它提供了请求队列和图片下载器(ImageLoader)的功能:
private static MySingleton mInstance;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private static Context mCtx; private MySingleton(Context context) {
mCtx = context;
mRequestQueue = getRequestQueue(); mImageLoader = new ImageLoader(mRequestQueue,
new ImageLoader.ImageCache() {
private final LruCache<String, Bitmap>
cache = new LruCache<String, Bitmap>(20); @Override
public Bitmap getBitmap(String url) {
return cache.get(url);
} @Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
});
} public static synchronized MySingleton getInstance(Context context) {
if (mInstance == null) {
mInstance = new MySingleton(context);
}
return mInstance;
} public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
// getApplicationContext() is key, it keeps you from leaking the
// Activity or BroadcastReceiver if someone passes one in.
mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
}
return mRequestQueue;
} public <T> void addToRequestQueue(Request<T> req) {
getRequestQueue().add(req);
} public ImageLoader getImageLoader() {
return mImageLoader;
}
}
下面是使用单例类处理请求队列操作的示例:
// Get a RequestQueue
RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()).
getRequestQueue();
... // Add a request (in this example, called stringRequest) to your RequestQueue.
MySingleton.getInstance(this).addToRequestQueue(stringRequest);
构建一个标准请求(Making a Standard Request)
这节课描述了如何使用Volley提供的一般请求类型:
-
StringRequest
. 指定一个网址(URL)和在相应里收到一个原始字符串. 在 Setting Up a Request Queue 有示例. -
ImageRequest
. 指定一个网址(URL)和在响应中收到图片. -
JsonObjectRequest
和JsonArrayRequest
(都是JsonRequest的子类
). 指定一个网址(URL)和获得一个JSON 对象或者JSON数组.
如果你期望的响应是上面这些中的一种,你可能不再需要实现自定义的请求。这节课描述了如何使用这些标准请求类型。更多关于自定义请求的内容请阅读Implementing a Custom Request.
请求一个图片(Request an Image)
Volley 提供了下面的类用来请求图片,这些类在它们彼此层次的顶层,提供不同程度的处理图片的支持:
-
ImageRequest(图片请求)
— 一个封装的请求,用于通过指定的URL获得一个图片和在对图片解码完毕后回调。它还提供了便利的特性比如指定一个将要调整到的尺寸。它非常有利的是,Volley的线程调度确保了昂贵的图片操作(比如解码,改变大小)等自动的在工作线程中执行。 -
ImageLoader(图片下载器)
— 一个辅助类,处理通过多个远程图片地址加载和缓存图片。ImageLoader是一个处理大量图片请求的控制台,比如在一个ListView中放置多个缩略图。ImageLoader 提供了一个内存缓存,以在Volley一般的缓存之上,对于防止闪烁这是非常重要的。这提供了一个可能性去实现一个缓存的击中,而不会在主线程阻塞或者发生延迟,如果使用 硬盘I/O 是不可能做到的。ImageLoader同时也做了响应合并,没有它,几乎每个响应处理器都会将图片显示在一个视图View上和导致每个图片发生一次布局(layout)操作。合并使得 同时传递多个响应 成为可能,它提升了性能。 -
NetworkImageView
— 以ImageLoader为基础和
有效的代替ImageView
在一些状况下,比如当你的图片通过一个网址在网络中被提取。NetworkImageView也管理着 在一个NetworkImageView被从视图层级中分离时终止等待中的请求。
使用 ImageRequest (Use ImageRequest)
下面是一个使用ImageRequest的示例。它通过一个URL获得图片并在应用中显示。注意这里使用单例模式和请求队里进行的交互。 (更多关于这个话题的讨论请阅读 training/volley/requestqueue.html#singleton">Setting Up a RequestQueue):
ImageView mImageView;
String url = "http://i.imgur.com/7spzG.png";
mImageView = (ImageView) findViewById(R.id.myImage);
... // Retrieves an image specified by the URL, displays it in the UI.
ImageRequest request = new ImageRequest(url,
new Response.Listener() {
@Override
public void onResponse(Bitmap bitmap) {
mImageView.setImageBitmap(bitmap);
}
}, 0, 0, null,
new Response.ErrorListener() {
public void onErrorResponse(VolleyError error) {
mImageView.setImageResource(R.drawable.image_load_error);
}
});
// Access the RequestQueue through your singleton class.
MySingleton.getInstance(this).addToRequestQueue(request);
使用 ImageLoader 和 NetworkImageView(Use ImageLoader and NetworkImageView)
你可以使用 ImageLoader
和 NetworkImageView
协调有效的管理大量图片的显示, 比如在 ListView中
.在你的布局 XML 文件中, 使用 NetworkImageView
和使用 ImageView 非常相似
, 例如:
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/networkImageView"
android:layout_width="150dp"
android:layout_height="170dp"
android:layout_centerHorizontal="true" />
你可以使用 ImageLoader
通过它自己来显示一个图片,例如:
ImageLoader mImageLoader;
ImageView mImageView;
// The URL for the image that is being loaded.
private static final String IMAGE_URL =
"http://developer.android.com/images/training/system-ui.png";
...
mImageView = (ImageView) findViewById(R.id.regularImageView); // Get the ImageLoader through your singleton class.
mImageLoader = MySingleton.getInstance(this).getImageLoader();
mImageLoader.get(IMAGE_URL, ImageLoader.getImageListener(mImageView,
R.drawable.def_image, R.drawable.err_image));
然而, 如果你的操作仅仅是显示图片在 ImageView中的话,那么 NetworkImageView
也可以做到这些你想做到的,例如:
ImageLoader mImageLoader;
NetworkImageView mNetworkImageView;
private static final String IMAGE_URL =
"http://developer.android.com/images/training/system-ui.png";
... // Get the NetworkImageView that will display the image.
mNetworkImageView = (NetworkImageView) findViewById(R.id.networkImageView); // Get the ImageLoader through your singleton class.
mImageLoader = MySingleton.getInstance(this).getImageLoader(); // Set the URL of the image that should be loaded into this view, and
// specify the ImageLoader that will be used to make the request.
mNetworkImageView.setImageUrl(IMAGE_URL, mImageLoader);
上面这些代码片段演示了通过一个单例类访问请求队列(RequestQueue)和图片下载(ImageLoader)的方式,更多描述见Setting Up a RequestQueue。这样的方式确保了你创建这些类的单个实例并且持续整个App的生命周期。非常重要的原因是对于ImageLoader(这个帮助类处理读取和缓存图片)来说,内存缓存的主要功能是做到了在翻转屏幕时不闪烁。使用一个单例模式允许位图缓存比activity活得长。如果你在Activity中创建了一个ImageLoader,这个ImageLoader将跟随activity,每次用户翻转设备时都会重新创建而发生屏幕闪烁。
LRU缓存示例(Example LRU cache)
Volley工具盒提供了基于DiskBasedCache类的标准缓存的实现。这个类缓存一个文件直接到硬盘上的指定文件夹。但是要使用ImageDownloader,你需要提供一个自定义的内存 LRU位图缓存并需要实现ImageLoader.ImageCache接口。你可以使用单例类设置你的缓存;更多讨论请阅读 Setting Up a RequestQueue.
下面的LruBitmapCache类是一个实现的示例。它继承自 LruCache
并实现了 ImageLoader.ImageCache
interface接口:
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
import android.util.DisplayMetrics;
import com.android.volley.toolbox.ImageLoader.ImageCache; public class LruBitmapCache extends LruCache<String, Bitmap>
implements ImageCache { public LruBitmapCache(int maxSize) {
super(maxSize);
} public LruBitmapCache(Context ctx) {
this(getCacheSize(ctx));
} @Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
} @Override
public Bitmap getBitmap(String url) {
return get(url);
} @Override
public void putBitmap(String url, Bitmap bitmap) {
put(url, bitmap);
} // Returns a cache size equal to approximately three screens worth of images.
public static int getCacheSize(Context ctx) {
final DisplayMetrics displayMetrics = ctx.getResources().
getDisplayMetrics();
final int screenWidth = displayMetrics.widthPixels;
final int screenHeight = displayMetrics.heightPixels;
// 4 bytes per pixel
final int screenBytes = screenWidth * screenHeight * 4; return screenBytes * 3;
}
}
下面演示了如何实例化一个ImageLoader和使用缓存:
RequestQueue mRequestQueue; // assume this exists.
ImageLoader mImageLoader = new ImageLoader(mRequestQueue, new LruBitmapCache(
LruBitmapCache.getCacheSize()));
请求JSON (Request JSON)
Volley 为JSON请求提供了下面的类:
-
JsonArrayRequest
— 通过一个指定的URL,发送请求到获得一个JSONArray
(JSON数组)响应体。 -
JsonObjectRequest
— 通过一个指定的URL,发送请求到获得一个JSONObject
(JSON对象)响应体,它允许一个可选的JSONObject对象作为参数通过作为请求体的一部分被传送。
这些类都是基于一般基础类JsonRequest的。你可以使用他们就像其他类型的请求一样,比如,下面的示例演示了提取一个JSON feed和以文本的形式在UI显示它。
Both classes are based on the common base class JsonRequest
. You use them following the same basic pattern you use for other types of requests. For example, this snippet fetches a JSON feed提要 and displays it as text in the UI:
TextView mTxtDisplay;
ImageView mImageView;
mTxtDisplay = (TextView) findViewById(R.id.txtDisplay);
String url = "http://my-json-feed"; JsonObjectRequest jsObjRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener() { @Override
public void onResponse(JSONObject response) {
mTxtDisplay.setText("Response: " + response.toString());
}
}, new Response.ErrorListener() { @Override
public void onErrorResponse(VolleyError error) {
// TODO Auto-generated method stub }
}); // Access the RequestQueue through your singleton class.
MySingleton.getInstance(this).addToRequestQueue(jsObjRequest);
要获得一个基于Gson的实习自定义JSON请求的示例,请阅读下一课, Implementing a Custom Request.
实现一个自定义请求(Implementing a Custom Request)
这节课描述了如何实现你的自定义请求类型,这些类型是没有被包含在 Volley支持的 out-of-the-box 类型的。
写一个自定义请求(Write a Custom Request)
在工具盒中,有很多请求是可以 准备-即用 的;如果你的响应是一个字符串,图片,或者JSON,或许你不再需要去实现一个自定义请求。
在那些你想要去实现自定义请求的情形中,这些时你需要做的:
- 继承
Request<T>
类, 在这里<T>
表示你的请求期望解析到的类型。如果你的解析后的响应是一个字符串,例如,创建你的自定义请求时要继承Request<String>。详情见更多Volley工具盒中的类StringRequest
和ImageRequest
继承自 Request<T>的示例。 - Implement the abstract methods
parseNetworkResponse()
anddeliverResponse()
, described in more detail below.
解析网络请求(parseNetworkResponse)
一个响应封装了一个解析后的响应用于传输,为了一个指定的类型(比如字符串,图片,或者JSON)。 下面是一个实现 parseNetworkResponse() 的示例:
@Override
protected Response<T> parseNetworkResponse(
NetworkResponse response) {
try {
String json = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(gson.fromJson(json, clazz),
HttpHeaderParser.parseCacheHeaders(response));
}
// handle errors
...
}
注意下面:
-
parseNetworkResponse()
有一个参数NetworkResponse
, 它包含了 装载了 字节数组 byte[] 的响应,HTTP状态码,和响应头。 - 你的实现必须返回一个
Response<T>
, 它包含了你的类型化的(强类型的)响应对象和缓存元数据,或者在解析失败时的错误
如果你的协议中包含了非标准的语义,你可以构造一个你自己的 Cache.Entry,但是大多数的请求像下面这样是好用的:
return Response.success(myDecodedObject,
HttpHeaderParser.parseCacheHeaders(response));
Volley 在一个工作现场中调用 parseNetworkResponse()
. 这确保了昂贵的解析操作比如对一个JPEG图像进行解码到一个位图对象中,不会阻塞UI线程。
传输响应 (deliverResponse)
Volley 使用你的 parseNetworkResponse()中返回的对象到主线程进行回调。许多请求在这里调用回调接口,例如:
protected void deliverResponse(T response) {
listener.onResponse(response);
GSON请求示例:GsonRequest(Example: GsonRequest)
Gson 是一个类库,使用反射的方法作用于互相转换Java对象和JSON 。你可以定义一个和那些JSON的键名称具有相同名称的字段的Java对象。将类的对象传递给GSON,而GSON将会为你自动填充这些字段的值。下面是一个使用GSON解析的Volley请求的完整的实现:
public class GsonRequest<T> extends Request<T> {
private final Gson gson = new Gson();
private final Class<T> clazz;
private final Map<String, String> headers;
private final Listener<T> listener; /**
* Make a GET request and return a parsed object from JSON.
*
* @param url URL of the request to make
* @param clazz Relevant class object, for Gson's reflection
* @param headers Map of request headers
*/
public GsonRequest(String url, Class<T> clazz, Map<String, String> headers,
Listener<T> listener, ErrorListener errorListener) {
super(Method.GET, url, errorListener);
this.clazz = clazz;
this.headers = headers;
this.listener = listener;
} @Override
public Map<String, String> getHeaders() throws AuthFailureError {
return headers != null ? headers : super.getHeaders();
} @Override
protected void deliverResponse(T response) {
listener.onResponse(response);
} @Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String json = new String(
response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(
gson.fromJson(json, clazz),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
}
}
}
Volley 提供了 准备-即用 的 JsonArrayRequest
和 JsonArrayObject
类, 如果你更加喜欢这种方式. 请阅读 Using Standard Request Types 获得更多信息。
(全文完结)