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项目:

  1. 使用Git克隆Volley仓库,在你的命令提示行下输入下面的内容:
    git clone https://android.googlesource.com/platform/frameworks/volley
  2. 导入下载的源代码到你的项目中,并且作为你的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选项卡中,使用他们各自的 选项卡对象 标记 它们自己的所有的 缩略图 请求,并在切换时触发终止操作,以确保 新的选项卡对象不会被 其他选项卡的请求 所持有。

下面是一个使用 字符串值作为标签 的示例:

1.定义你的标签并且添加到你的请求上。

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

2.在你的 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获得图片并在应用中显示。注意这里使用单例模式和请求队里进行的交互。 (更多关于这个话题的讨论请阅读 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() and deliverResponse(), 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 获得更多信息。

(全文完结)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容