Transmitting Network Data Using Volley(使用Volley框架传输网络数据)

前面看了某大神关于Volley框架的文章,难怪说不要国内的技术文章,看了Google的官方文档,我才知道,心目中的大神还是有很多不足的地方。所以,对着英文,自己学习下。

Volley is an HTTP library that makes networking for Android apps easier and most importantly, faster. Volley is available through the open AOSP repository.

Volley框架是http的library,并且开源在Android Open Source Project上,它使得网络对于Android的app更加的容易、重要和迅速。

Volley offers the following benefits:

  • Automatic scheduling of network requests.自动调度网络请求
  • Multiple concurrent network connections.多个并发的网络连接
  • Transparent disk and memory response caching with standard HTTP cache coherence.使用标准的高速缓存一致性的透明的硬盘和内存响应缓存。(翻译的不知道对不对,不理解这句话)
  • Support for request prioritization.支持请求的优先级
  • Cancellation request API. You can cancel a single request, or you can set blocks or scopes of requests to cancel.取消请求API。你可以取消一个请求,也可以设置请求取消的块或范围。
  • Ease of customization, for example, for retry and backoff.易于定制
  • Strong ordering that makes it easy to correctly populate your UI with data fetched asynchronously from the network.强序使得很容易的通过异步方式从网络正确的得到数据,填充到UI界面上。
  • Debugging and tracing tools.debug和跟踪的工具。

Volley excels at RPC-type operations used to populate a UI, such as fetching a page of search results as structured data. It integrates easily with any protocol and comes out of the box with support for raw strings, images, and JSON. By providing built-in support for the features you need, Volley frees you from writing boilerplate code and allows you to concentrate on the logic that is specific to your app.

Volley框架擅长于RPC类型(RPC(Remote Procedure Call Protocol)——远程过程调用协议)的操作,这些操作用于填充UI,例如抓取搜索的结果数据。

他可以与任何的协议结合,并且支持原始的字符串,图片,和JSON。通过提供内置的支持,可以让你免去写模板代码,专注于app的逻辑。


Volley is not suitable for large download or streaming operations, since Volley holds all responses in memory during parsing. For large download operations, consider using an alternative like DownloadManager.

Volley框架不适用于大型的下载或者流操作。因为Volley框架在解析的过程中在内存中保持着所有的连接。对于大型的下载操作,建议适用DownloadManager类。

The core Volley library is developed in the open AOSP repository at frameworks/volley and contains the main request dispatch pipeline as well as a set of commonly applicable utilities, available in the Volley "toolbox." The easiest way to add Volley to your project is to clone the Volley repository and set it as a library project.

把Volley的jar包直接导入即可。

Sending a Simple Request

At a high level, you use Volley by creating a RequestQueue and passing it Request objects. The RequestQueue manages worker threads for running the network operations, reading from and writing to the cache, and parsing responses. Requests do the parsing of raw responses and Volley takes care of dispatching the parsed response back to the main thread for delivery.

很大程度上,我们在使用Volley框架的时候,创建一个RequestQueue 对象并把Request 对象传给他。RequestQueue 管理网络操作的线程,这些线程用于从缓存中读取,写入到缓存中,解析请求。Volley调度已解析的请求并交付给主线程。

This lesson describes how to send a request using theVolley.newRequestQueue convenience method, which sets up aRequestQueue for you. See the next lesson, Setting Up a RequestQueue, for information on how to set up a RequestQueueyourself.

第一步:Add the INTERNET Permission

添加权限,使用Volley的第一步是在清单文件中配置权限。

第二步:Use newRequestQueue

Volley provides a convenience method Volley.newRequestQueue that sets up a RequestQueue for you, using default values, and starts the queue. For example:

通过Volley.newRequestQueuesets up a RequestQueue。

package com.dy.ustc.volley;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {

	private TextView tv_display;
	


	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		tv_display = (TextView) findViewById(R.id.tv_display);
		// Instantiate the RequestQueue.
		RequestQueue queue = Volley.newRequestQueue(this);
		String url = "http://www.baidu.com";

		StringRequest stringRequest = new StringRequest(Request.Method.GET,
				url, new Response.Listener<String>() {

					@Override
					public void onResponse(String response) {
						tv_display.setText("Response is:" + response);
					}
				}, new Response.ErrorListener() {

					@Override
					public void onErrorResponse(VolleyError error) {
						tv_display.setText("That did not work");
					}
				});
		queue.add(stringRequest);
	}
}<span style="color:#006600;">
</span>

得到下面的结果:


Volley always delivers parsed responses on the main thread. Running on the main thread is convenient for populating UI controls with received data, as you can freely modify UI controls directly from your response handler, but it's especially critical to many of the important semantics provided by the library, particularly related to canceling requests.

Volley将已解析的响应提交给主线程。运行在主线程上对于使用接收到的数据来填充UI很方便。你可以直接通过响应自由的修改UI,同时很多重要的语义也是很重要的,特别是与取消请求相关的。

第三步:Send a Request

To send a request, you simply construct one and add it to the RequestQueue with add(), as shown above. Once you add the request it moves through the pipeline, gets serviced, and has its raw response parsed and delivered.

发送一个请求只需要将他构造出来,然后扔进请求队列中即可。如上面的代码。

When you call add(), Volley runs one cache processing thread and a pool of network dispatch threads. When you add a request to the queue, it is picked up by the cache thread and triaged: if the request can be serviced from cache, the cached response is parsed on the cache thread and the parsed response is delivered on the main thread. If the request cannot be serviced from cache, it is placed on the network queue. The first available network thread takes the request from the queue, performs the HTTP transaction, parsse the response on the worker thread, writes the response to cache, and posts the parsed response back to the main thread for delivery.

Note that expensive operations like blocking I/O and parsing/decoding are done on worker threads. You can add a request from any thread, but responses are always delivered on the main thread.

当使用add()方法的时候,Volley runs一个缓存过程的线程和一个网络调度的线程池。当把请求扔进请求队列的时候,通过缓存线程得到,并被触发。

request的生命周期如下:


第四步;Cancel a Request

To cancel a request, call cancel() on your Request object. Once cancelled, Volley guarantees that your response handler will never be called. What this means in practice is that you can cancel all of your pending requests in your activity's onStop() method and you don't have to litter your response handlers with checks forgetActivity() == null, whether onSaveInstanceState() has been called already, or other defensive boilerplate.

To take advantage of this behavior, you would typically have to track all in-flight requests in order to be able to cancel them at the appropriate time. There is an easier way: you can associate a tag object with each request. You can then use this tag to provide a scope of requests to cancel. For example, you can tag all of your requests with the Activity they are being made on behalf of, and call requestQueue.cancelAll(this) from onStop(). Similarly, you could tag all thumbnail image requests in a ViewPager tab with their respective tabs and cancel on swipe to make sure that the new tab isn't being held up by requests from another one.

通过使用TAG,在onStop方法中取消。
<span style="font-size:10px;">package com.dy.ustc.volley;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {

	public static final Object TAG = "MainActivity";

	private TextView tv_display;
	
	RequestQueue queue;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		tv_display = (TextView) findViewById(R.id.tv_display);
		// Instantiate the RequestQueue.
		 queue = Volley.newRequestQueue(this);
		String url = "http://www.baidu.com";

		StringRequest stringRequest = new StringRequest(Request.Method.GET,
				url, new Response.Listener<String>() {

					@Override
					public void onResponse(String response) {
						tv_display.setText("Response is:" + response);
					}
				}, new Response.ErrorListener() {

					@Override
					public void onErrorResponse(VolleyError error) {
						tv_display.setText("That did not work");
					}
				});
		stringRequest.setTag(TAG);
		queue.add(stringRequest);
	}
	@Override
	protected void onStop() {
		super.onStop();
		if (queue != null) {
			queue.cancelAll(TAG);
		}
	}
}</span><span style="font-size:24px;">
</span>

Setting Up a RequestQueue


The previous lesson showed you how to use the convenience method Volley.newRequestQueue to set up a RequestQueue, taking advantage of Volley's default behaviors. This lesson walks you through the explicit steps of creating a RequestQueue, to allow you to supply your own custom behavior.

This lesson also describes the recommended practice of creating a RequestQueue as a singleton, which makes theRequestQueue last the lifetime of your app.

上面通过   Volley.newRequestQueue  to set up a  RequestQueue,This lesson通过将RequestQueue作为单例创建。通过这样使得RequestQueue持续应用程序的整个的生命周期。
第一步: Set Up a Network and Cache

RequestQueue needs two things to do its job: a network to perform transport of the requests, and a cache to handle caching. There are standard implementations of these available in the Volley toolbox: DiskBasedCache provides a one-file-per-response cache with an in-memory index, and BasicNetwork provides a network transport based on your choice of AndroidHttpClient or HttpURLConnection.

BasicNetwork is Volley's default network implementation. A BasicNetwork must be initialized with the HTTP client your app is using to connect to the network. Typically this is AndroidHttpClient or HttpURLConnection:

RequestQueue请求队列需要这样两样东西去做他的工作:一是网络去传输他的请求,而是缓存。
DiskBasedCache 提供了在内存索引上的单文件单响应缓存,BasicNetwork 提供了网络传输的需求。基于 AndroidHttpClient or HttpURLConnection.。
AndroidHttpClient低于API 9可以使用。
 HttpURLConnection  高于API 9使用。
To create an app that runs on all versions of Android, you can check the version of Android the device is running and choose the appropriate HTTP client, for example:
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);

This snippet shows you the steps involved in setting up a  RequestQueue :
package com.dy.ustc.volley;

import com.android.volley.Cache;
import com.android.volley.Network;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.BasicNetwork;
import com.android.volley.toolbox.DiskBasedCache;
import com.android.volley.toolbox.HurlStack;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity1 extends Activity {

	private TextView tv_display;
	
	RequestQueue mRequestQueue;
	
	Cache cache;
	

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		tv_display = (TextView) findViewById(R.id.tv_display);
		String url = "http://www.baidu.com";
		// Instantiate the cache
		cache = new DiskBasedCache(getCacheDir(), 1024*1024);
		// 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();
		StringRequest stringRequest = new StringRequest(Request.Method.GET,
				url, new Response.Listener<String>() {

					@Override
					public void onResponse(String response) {
						tv_display.setText("Response is:" + response);
					}
				}, new Response.ErrorListener() {

					@Override
					public void onErrorResponse(VolleyError error) {
						tv_display.setText("That did not work");
					}
				});
		mRequestQueue.add(stringRequest);
	}
}

If you just need to make a one-time request and don't want to leave the thread pool around, you can create the RequestQueue  wherever you need it and call  stop()  on the  RequestQueue  once your response or error has come back, using the  Volley.newRequestQueue()  method described in  Sending a Simple Request . But the more common use case is to create the  RequestQueue  as a singleton to keep it running for the lifetime of your app, as described in the next section.
如果你需要创建一次的请求而不希望留下线程池,你可以在你需要的时候创建和停止。通常情况下,我们用单例模式创建RequestQueue。
第二步: Use a Singleton Pattern

If your application makes constant use of the network, it's probably most efficient to set up a single instance ofRequestQueue that will last the lifetime of your app. You can achieve this in various ways. The recommended approach is to implement a singleton class that encapsulates RequestQueue and other Volley functionality. Another approach is to subclass Application and set up the RequestQueue in Application.onCreate(). But this approach is discouraged; a static singleton can provide the same functionality in a more modular way.

单例类封装了需要的方法,如下的代码。不需要再Application的onCreate()方法中创建请求队列对象了。

A key concept is that the RequestQueue must be instantiated with the Application context, not an Activitycontext. This ensures that the RequestQueue will last for the lifetime of your app, instead of being recreated every time the activity is recreated (for example, when the user rotates the device).

一个关键点:需要使用getApplicationContext,而不是Activity的context,因为getApplicationContext的生命周期和app的生命周期一样,但是Activity的Context生命周期会随着Activity的死亡和终结,随着Activity的重建而重建。比如当用户旋转了屏幕(此时Activity的生命周期会发生改变)

Here is an example of a singleton class that provides RequestQueue and ImageLoader functionality:

package com.dy.ustc.volley;

import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageLoader.ImageCache;
import com.android.volley.toolbox.Volley;

public class MySingleton {

	private static MySingleton mInstance;
	private ImageLoader mImageLoader;
	private RequestQueue mRequestQueue;
	private static Context mCtx;

	private MySingleton(Context context) {
		mCtx = context;
		mRequestQueue = getRequestQueue();

		mImageLoader = new ImageLoader(mRequestQueue, new ImageCache() {

			private final LruCache<String, Bitmap> cache = new LruCache<String, Bitmap>(
					20);

			@Override
			public void putBitmap(String url, Bitmap bitmap) {
				cache.put(url, bitmap);
			}

			@Override
			public Bitmap getBitmap(String url) {
				return cache.get(url);
			}
		});
	}

	public static synchronized MySingleton getInstance(Context context) {
		if (mInstance == null) {
			mInstance = new MySingleton(context);
		}
		return mInstance;
	}

	public RequestQueue getRequestQueue() {
		if (mRequestQueue == null) {
			mRequestQueue = Volley
					.newRequestQueue(mCtx.getApplicationContext());
		}
		return mRequestQueue;
	}

	public <T> void addToRequestQueue(Request<T> req) {
		getRequestQueue().add(req);
	}

	public ImageLoader getImageLoader() {
		return mImageLoader;
	}

}

使用:

package com.dy.ustc.volley;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity2 extends Activity {

	private TextView tv_display;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		tv_display = (TextView) findViewById(R.id.tv_display);
		String url = "http://www.baidu.com";
		RequestQueue queue = MySingleton.getInstance(
				this.getApplicationContext()).getRequestQueue();
		StringRequest stringRequest = new StringRequest(Request.Method.GET,
				url, new Response.Listener<String>() {

					@Override
					public void onResponse(String response) {
						tv_display.setText("Response is:" + response);
					}
				}, new Response.ErrorListener() {

					@Override
					public void onErrorResponse(VolleyError error) {
						tv_display.setText("That did not work");
					}
				});
		MySingleton.getInstance(this).addToRequestQueue(stringRequest);
	}
}

Making a Standard Request


This lesson describes how to use the common request types that Volley supports:

  • StringRequest. Specify a URL and receive a raw string in response. See Setting Up a Request Queue for an example.
  • ImageRequest. Specify a URL and receive an image in response.
  • JsonObjectRequest and JsonArrayRequest (both subclasses of JsonRequest). Specify a URL and get a JSON object or array (respectively) in response.
Volley框架支持的请求的类型。
1.StringRequest
2.ImageRequest
3.JsonObjectRequest(JsonArrayRequest)

Request an Image


Volley offers the following classes for requesting images. These classes layer on top of each other to offer different levels of support for processing images:

  • ImageRequest—a canned request for getting an image at a given URL and calling back with a decoded bitmap. It also provides convenience features like specifying a size to resize to. Its main benefit is that Volley's thread scheduling ensures that expensive image operations (decoding, resizing) automatically happen on a worker thread.
  • ImageLoader—a helper class that handles loading and caching images from remote URLs. ImageLoader is a an orchestrator for large numbers of ImageRequests, for example when putting multiple thumbnails in aListViewImageLoader provides an in-memory cache to sit in front of the normal Volley cache, which is important to prevent flickering. This makes it possible to achieve a cache hit without blocking or deferring off the main thread, which is impossible when using disk I/O. ImageLoader also does response coalescing, without which almost every response handler would set a bitmap on a view and cause a layout pass per image. Coalescing makes it possible to deliver multiple responses simultaneously, which improves performance.
  • NetworkImageView—builds on ImageLoader and effectively replaces ImageView for situations where your image is being fetched over the network via URL. NetworkImageView also manages canceling pending requests if the view is detached from the hierarchy.
Volley提供了下面的类用来请求images.

1.ImageRequest---通过给定的URL获取images,调用后返回一个已解码的bitmap。他提供了一些方便的特性,比如重新调整图片的大小。他最好的在于线程调度保证了一些昂贵的操作(比如解码,重调整大小)自动发生在worker thread上。

2.ImageLoader---ImageLoader是一个辅助类,用来处理从远程URL加载和缓存图像的功能。ImageLoader 是一个协调器,用于处理大量数量的ImageRequests.例如将多个缩略图加载到ListView中。ImageLoader provides an in-memory cache(存储器缓存) to sit in front of the normal Volley cache, which is important to prevent flickering(闪烁).这使得在不阻塞或延迟关闭主线程的前提下实现cache hit。ImageLoader 同时有凝聚式的响应,如果没有这些凝聚式的响应,几乎每个响应请求会在view上加载一个bitmap,并且会导致每个图像的布局传递。凝聚式的响应使得同时处理多响应成为可能,这也提高了性能。

3.NetworkImageView---建立在ImageLoader之上,可以有效的替换ImageView,在这种场合下使用:image is being fetched over the network via URL。如果View从层次上分离开来,NetworkImageView还管理取消挂起的请求。

Use ImageRequest

Here is an example of using ImageRequest. It retrieves the image specified by the URL and displays it in the app. Note that this snippet interacts with the RequestQueue through a singleton class 

package com.dy.ustc.volley;

import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageRequest;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.Window;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity3 extends Activity {

	private ImageView mImageView;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		mImageView = (ImageView) findViewById(R.id.tv_display);
		String url = "http://g.hiphotos.baidu.com/album/w=2048;q=75/sign=566d52a4bd3eb13544c7b0bb922693a2/6f061d950a7b0208ad9341ad63d9f2d3572cc820.jpg";
		// Retrieves an image specified by the URL, displays it in the UI.
		ImageRequest request = new ImageRequest(url, 
				new Response.Listener<Bitmap>() {

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

			
		}, 0, 0, null, new Response.ErrorListener() {

			@Override
			public void onErrorResponse(VolleyError error) {
				Toast.makeText(MainActivity3.this, "err", 0).show();
			}
		});
		// Access the RequestQueue through your singleton class.
		MySingleton.getInstance(this).addToRequestQueue(request);
	}
}

Use ImageLoader and NetworkImageView

You can use ImageLoader and NetworkImageView in concert to efficiently manage the display of multiple images, such as in a ListView. In your layout XML file, you use NetworkImageView in much the same way you would useImageView, for example:

<com.android.volley.toolbox.NetworkImageView
        android:id="@+id/networkImageView"
        android:layout_width="150dp"
        android:layout_height="170dp"
        android:layout_centerHorizontal="true" />

package com.dy.ustc.volley;

import com.android.volley.toolbox.ImageLoader;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.widget.ImageView;

public class MainActivity3 extends Activity {

	private ImageView mImageView;
	private ImageLoader mImageLoader;
	private static final String IMAGE_URL = "http://g.hiphotos.baidu.com/album/w=2048;q=75/sign=35f2f91a500fd9f9a01752691115ef5b/71cf3bc79f3df8dc0f0a59f7cc11728b471028a5.jpg";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		mImageView = (ImageView) findViewById(R.id.tv_display);
		mImageLoader = MySingleton.getInstance(this).getImageLoader();  
		
		mImageLoader.get(IMAGE_URL, ImageLoader.getImageListener(mImageView, R.drawable.ic_launcher, R.drawable.ic_launcher));
		
	}
}


However, NetworkImageView can do this for you if all you're doing is populating an ImageView. For example:

package com.dy.ustc.volley;

import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.NetworkImageView;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;

public class MainActivity5 extends Activity {

	private NetworkImageView mImageView;
	private ImageLoader mImageLoader;
	private static final String IMAGE_URL = "http://d.hiphotos.baidu.com/album/w=2048;q=75/sign=c6e0240a113853438ccf8021a72b8b0f/d31b0ef41bd5ad6e2e0eb38c80cb39dbb7fd3ce5.jpg";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		mImageView = (NetworkImageView) findViewById(R.id.tv_display);
		// 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.
		mImageView.setImageUrl(IMAGE_URL, mImageLoader);
		
	}
}


The above snippets access the  RequestQueue  and the  ImageLoader  through a singleton class, as described in Setting Up a RequestQueue . This approach ensures that your app creates single instances of these classes that last the lifetime of your app. The reason that this is important for  ImageLoader  (the helper class that handles loading and caching images) is that the main function of the in-memory cache is to allow for flickerless rotation. Using a singleton pattern allows the bitmap cache to outlive the activity. If instead you create the ImageLoader  in an activity, the  ImageLoader  would be recreated along with the activity every time the user rotates the device. This would cause flickering.
使用单例类的生命周期是整个应用的生命周期,这样会避免闪烁问题。
Example LRU cache

The Volley toolbox provides a standard cache implementation via the DiskBasedCache class. This class caches files directly onto the hard disk in the specified directory. But to use ImageLoader, you should provide a custom in-memory LRU bitmap cache that implements the ImageLoader.ImageCache interface. You may want to set up your cache as a singleton; for more discussion of this topic, see Setting Up a RequestQueue.

Here is a sample implementation for an in-memory LruBitmapCache class. It extends the LruCache class and implements the ImageLoader.ImageCache interface:

结合LRU cache使用的例子:
package com.dy.ustc.volley;

import android.content.Context;
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){
		DisplayMetrics displayMetrics = ctx.getResources().getDisplayMetrics();
		int screenWidth  = displayMetrics.widthPixels;
		int screenHeight  = displayMetrics.heightPixels;
		 // 4 bytes per pixel
		int screenBytes = screenWidth * screenHeight * 4;
		
		return screenBytes * 3;
	}
	
	
}

调用:
package com.dy.ustc.volley;

import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.NetworkImageView;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.widget.ImageView;

public class MainActivity6 extends Activity {

	private NetworkImageView mImageView;
	private ImageLoader mImageLoader;
	private RequestQueue queue;
	public static final String IMAGE_URL = "http://g.hiphotos.baidu.com/album/w=2048;q=75/sign=22f2aaadfaedab6474724ac0c30e94b2/9213b07eca8065388a2a707596dda144ac348290.jpg";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		queue = MySingleton.getInstance(
				this.getApplicationContext()).getRequestQueue();
		mImageView = (NetworkImageView) findViewById(R.id.tv_display);
		mImageLoader = new ImageLoader(queue, new LruBitmapCache(LruBitmapCache.getCacheSize(getApplicationContext())));
		// 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.
		mImageView.setImageUrl(IMAGE_URL, mImageLoader);
		
	}
}

RequestQueue要通过单例类实例化,否则会NPE异常。


Request JSON


Volley provides the following classes for JSON requests:

  • JsonArrayRequest—A request for retrieving a JSONArray response body at a given URL.
  • JsonObjectRequest—A request for retrieving a JSONObject response body at a given URL, allowing for an optional JSONObject to be passed in as part of the request body.

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:

package com.dy.ustc.volley;

import org.json.JSONObject;

import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.widget.TextView;

public class MainActivity7 extends Activity {

	private TextView tv_display;
	String url = "http://www.weather.com.cn/data/cityinfo/101010100.html";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);

		tv_display = (TextView) findViewById(R.id.tv_display); 

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

					@Override
					public void onResponse(JSONObject response) {
						tv_display.setText(response.toString());
					}
				}, new Response.ErrorListener() {

					@Override
					public void onErrorResponse(VolleyError error) {
						tv_display.setText("错误");
					}
				});
		MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest);
	}
}



Implementing a Custom Request


This lesson describes how to implement your own custom request types, for types that don't have out-of-the-box Volley support.
实现自己自定义的请求类型。

Write a Custom Request


Most requests have ready-to-use implementations in the toolbox; if your response is a string, image, or JSON, you probably won't need to implement a custom  Request .

For cases where you do need to implement a custom request, this is all you need to do:

  • Extend the Request<T> class, where <T> represents the type of parsed response the request expects. So if your parsed response is a string, for example, create your custom request by extending Request<String>. See the Volley toolbox classes StringRequest and ImageRequest for examples of extending Request<T>.
  • Implement the abstract methods parseNetworkResponse() and deliverResponse(), described in more detail below.
实现自定义的需要:
第一:继承Request<T> 类,T可以是String,等等;
第二:实现抽象方法:parseNetworkResponse() and deliverResponse()

parseNetworkResponse

Response encapsulates a parsed response for delivery, for a given type (such as string, image, or JSON). Here is a sample implementation of 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
...
}

Note the following:

  • parseNetworkResponse() takes as its parameter a NetworkResponse, which contains the response payload as a byte[], HTTP status code, and response headers.
  • Your implementation must return a Response<T>, which contains your typed response object and cache metadata or an error, such as in the case of a parse failure.

If your protocol has non-standard cache semantics, you can build a Cache.Entry yourself, but most requests are fine with something like this:

return Response.success(myDecodedObject,
        HttpHeaderParser.parseCacheHeaders(response));
Volley calls  parseNetworkResponse()  from a worker thread. This ensures that expensive parsing operations, such as decoding a JPEG into a Bitmap, don't block the UI thread.
volley框架在worker thread调用parseNetworkResponse  方法,保证了主线程不会被阻塞。

deliverResponse

Volley calls you back on the main thread with the object you returned in parseNetworkResponse(). Most requests invoke a callback interface here, for example:

protected void deliverResponse(T response) {
        listener.onResponse(response);

 

Example: GsonRequest

Gson is a library for converting Java objects to and from JSON using reflection. You can define Java objects that have the same names as their corresponding JSON keys, pass Gson the class object, and Gson will fill in the fields for you. Here's a complete implementation of a Volley request that uses Gson for parsing:

本案例实现天气预报。
接口参考:
http://blog.csdn.net/hello_haozi/article/details/7564223
返回的json格式如下:
{"weatherinfo":{"city":"厦门","city_en":"xiamen","date_y":"2014年12月6日","date":"十月十五","week":"星期六","fchh":"11","cityid":"101230201","temp1":"19℃~12℃","temp2":"20℃~13℃","temp3":"21℃~13℃","temp4":"19℃~14℃","temp5":"20℃~15℃","temp6":"21℃~15℃","tempF1":"66.2℉~53.6℉","tempF2":"68℉~55.4℉","tempF3":"69.8℉~55.4℉","tempF4":"66.2℉~57.2℉","tempF5":"68℉~59℉","tempF6":"69.8℉~59℉","weather1":"多云","weather2":"多云","weather3":"多云","weather4":"多云","weather5":"多云","weather6":"多云","img1":"1","img2":"99","img3":"1","img4":"99","img5":"1","img6":"99","img7":"1","img8":"99","img9":"1","img10":"99","img11":"1","img12":"99","img_single":"1","img_title1":"多云","img_title2":"多云","img_title3":"多云","img_title4":"多云","img_title5":"多云","img_title6":"多云","img_title7":"多云","img_title8":"多云","img_title9":"多云","img_title10":"多云","img_title11":"多云","img_title12":"多云","img_title_single":"多云","wind1":"微风","wind2":"微风","wind3":"微风","wind4":"微风","wind5":"微风","wind6":"微风","fx1":"微风","fx2":"微风","fl1":"小于3级","fl2":"小于3级","fl3":"小于3级","fl4":"小于3级","fl5":"小于3级","fl6":"小于3级","index":"较舒适","index_d":"建议着薄外套、开衫牛仔衫裤等服装。年老体弱者应适当添加衣物,宜着夹克衫、薄毛衣等。","index48":"","index48_d":"","index_uv":"弱","index48_uv":"","index_xc":"较适宜","index_tr":"适宜","index_co":"舒适","st1":"19","st2":"12","st3":"20","st4":"13","st5":"21","st6":"13","index_cl":"较适宜","index_ls":"适宜","index_ag":"极不易发"}}

定义java bean类:

package com.dy.ustc.volley;

public class WeatherInfo {
	private String city;

	private String temp1;

	private String date_y;

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getTemp1() {
		return temp1;
	}

	public void setTemp1(String temp1) {
		this.temp1 = temp1;
	}

	public String getDate_y() {
		return date_y;
	}

	public void setDate_y(String date_y) {
		this.date_y = date_y;
	}




}
package com.dy.ustc.volley;

public class Weather {
	private WeatherInfo weatherinfo;

	public WeatherInfo getWeatherinfo() {
		return weatherinfo;
	}

	public void setWeatherinfo(WeatherInfo weatherinfo) {
		this.weatherinfo = weatherinfo;
	}
}

布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/txt_theme36" >

    <TextView
        android:id="@+id/tv_city"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="150dp"
        android:layout_centerInParent="true"
        android:text="合肥"
        android:textSize="30dp" />

    <TextView
        android:id="@+id/tv_temp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tv_city"
        android:gravity="center"
        android:text="温度"
        android:textSize="30dp" />

    <TextView
        android:id="@+id/tv_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tv_temp"
        android:gravity="center"
        android:text="时间"
        android:textSize="30dp" />

</RelativeLayout>


自定义的GsonRequest:
package com.dy.ustc.volley;

import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
import android.widget.TextView;

public class MainActivity8 extends Activity {

	private TextView tv_city;
	private TextView tv_temp;
	private TextView tv_time;
	RequestQueue queue;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		tv_city = (TextView) findViewById(R.id.tv_city);
		tv_temp = (TextView) findViewById(R.id.tv_temp);
		tv_time = (TextView) findViewById(R.id.tv_time);
		
		GsonRequest<Weather> gsonRequest = new GsonRequest<Weather>(
				"http://m.weather.com.cn/atad/101220101.html",
				Weather.class, new Response.Listener<Weather>() {
					@Override
					public void onResponse(Weather weather) {
						WeatherInfo weatherInfo = weather.getWeatherinfo();
						tv_city.setText("城市:" + weatherInfo.getCity());
						tv_temp.setText("温度:" + weatherInfo.getTemp1());
						tv_time.setText("日期:" + weatherInfo.getDate_y());
						
					}
				}, new Response.ErrorListener() { 
					@Override
					public void onErrorResponse(VolleyError error) {
						Log.e("TAG", error.getMessage(), error);
					}
				});
		MySingleton.getInstance(this).addToRequestQueue(gsonRequest);
	}
}

效果图:

到此为止,volley框架的内容告一段落。
(可以基于此做一个天气预报的APP了)

希望和大家一起交流。

我的QQ:3067863573.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值