Android训练课程(Android Training) - 使用Volley传输网络数据(Transmitting Network Data Using Volley)
使用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 插图说明一个请求的生命周期:
中断一个请求(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);
(全文完结)