Volley 的介绍和使用(三)

来源:互联网 发布:手机上网代理软件 编辑:程序博客网 时间:2024/05/22 04:41

这一节我们介绍自定义Request。
在上一节中我们只介绍了StringRequest的POST的请求方式,而没有介绍JsonObjectRequestJsonArrayReqest的POST请求方式,因为这两个扩展至Request的类,覆盖了getBody()方法,把Request的encode 请求参数的方法修改了,把构造函数中的JSONObject对象转换成String, 直接发送出去了;所以我们要实现POST请求,需要自己实现一个Request

自定义Request

自己自定义一个Request,需要继承Request类,类似于StringRequest中的实现。主要重写一下parseNetworkResponse()方法,这个方法用来解析网络请求的结果。以下是 StringRequst 的源码:

public class StringRequest extends Request<String> {    //用于传递请求结果的监听器    private final Listener<String> mListener;    //根据给出的请求方式,创建一个新的请求    public StringRequest(int method, String url, Listener<String> listener,            ErrorListener errorListener) {        super(method, url, errorListener);        mListener = listener;    }    //创建一个GET 请求        public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {        this(Method.GET, url, listener, errorListener);    }    @Override    protected void deliverResponse(String response) {        mListener.onResponse(response);//传递请求结果    }    //这个方法主要是将请求返回的数据进行解析等处理    @Override    protected Response<String> parseNetworkResponse(NetworkResponse response) {        String parsed;        try {            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));        } catch (UnsupportedEncodingException e) {            parsed = new String(response.data);        }        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));    }}

类似我们创建一个JsonPostRequest:

public class JsonPostRequest extends Request<JSONObject> {    //用于传递请求结果的监听器    public Response.Listener<JSONObject> mListener;    private Map<String, String> mParames;    //根据给出的请求方式,创建一个新的请求    private JsonPostRequest(@PostOnly int method, String url, Map<String, String> parames, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {        super(method, url, errorListener);        this.mParames = parames;        this.mListener = listener;    }    //创建一个POST请求    public JsonPostRequest(String url, Map<String, String> parames, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {        this(POST, url, parames, listener, errorListener);    }    // 获取请求参数    @Override    protected Map<String, String> getParams() throws AuthFailureError {        return mParames;    }    /**     * //这个方法主要是将请求返回的数据进行解析等处理     * @param response Response from the network     * @return Response 对象,包含解析过的数据     */    @Override    protected Response parseNetworkResponse(NetworkResponse response) {        String parsed;        try {            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));            //将数据封装成JSONObject            return Response.success(new JSONObject(parsed), HttpHeaderParser.parseCacheHeaders(response));        } catch (JSONException e) {            return Response.error(new ParseError(e));        } catch (UnsupportedEncodingException e) {            return Response.error(new ParseError(e));        }    }    @Override    protected void deliverResponse(JSONObject response) {        mListener.onResponse(response);//传递请求结果    }    public static final int POST = Method.POST;    /**     * 创建一个注解,用来限制参数类型,这里只能传入POST这个参数     */    @IntDef({POST})    public @interface PostOnly {    }}

这样我们就可以得到一个请求返回是JSONObject的请求类了。我们可以这样使用它。

private void requestByVolley(){    //1.组拼URL    String mUrlStr = "http://op.juhe.cn/onebox/news/query";    //2.获取一个RequestQueue    RequestQueue queue = App.getQueue();    //3.设置POST请求的参数    Map<String, String> parames = new HashMap<>();    parames.put("q", "普京");//搜索关于普京的新闻    parames.put("key", APP_KEY);    //4.创建一个请求,其返回的结果以String 形式返回    JsonPostRequest requst = new JsonPostRequest(mUrlStr, parames,            new Response.Listener<JSONObject>() {                @Override                public void onResponse(JSONObject response) {                    mTextView.setText(response.toString());                }            },            new Response.ErrorListener() {                @Override                public void onErrorResponse(VolleyError error) {                    mTextView.setText(error.getMessage());                }            });    //5.将请求添加的请求队列中,在这里请求就已经开始了    queue.add(requst);}

使用方式类似于之前的 JsonObjectRequst 的GET请求方式;类似的我么也可以做其它形式的扩展,例如可以返回 JSONArray ,可以返回某个需要的对象,当然也可以把 Gson 嵌入进去。只需要 修改一下 parseNetworkResponse()就OK,在这里做你想要的操作。

ImageLoader

上一节介绍了 ImageRequest ,可以很简单的实现对网络图片的请求。但是这种方式是没有的缓存的,如果需要缓存就需要 ImageLoader ;它的内部实现其实也是使用ImageRequest实现的,当然ImageLoaderImageRequest更高一些,它不仅仅对图片进行了缓存还过滤了重复的链接,避免重复请求;当然使用也稍微麻烦一些。

ImageLoader 的构造方法中,需要一个RequestQueue 和一个ImageCache

public ImageLoader(RequestQueue queue, ImageCache imageCache) {    mRequestQueue = queue;    mCache = imageCache;}

所以我们需要一个 RequestQueue 和一个ImageCache 。当然如果我们还需要一个监听器,用来监听下载图片是否成功,如果成功就显示下载的图片,如果失败就显示失败图片,在下载过程中,我们不能让界面空着,也要给它一个默认图片。当然ImageLoader提供了这样的监听器 ImageListener。下面看看它:

ImageLoader.ImageListener listener = ImageLoader.getImageListener(mImageView, R.drawable.default_icon, R.drawable.error_icon);

上面的方法的第一个参数,是要显示图片的控件;第二个参数是默认图;第三个图片是下载失败要显示的图片。

最后我们只需要在调用 ImageLoaderget()方法就OK了。
上面说的比较简单,下面我们上代码。

private void loadImageByImageLoader() {    //1.图片的URL    String imageURL = "http://c.hiphotos.baidu.com/image/pic/item/0dd7912397dda1449fad6f63b6b7d0a20df486be.jpg";    //2.请求队列    RequestQueue queue = App.getQueue();    //3.使用请求队列和ImageCache构造一个ImageLoader    ImageLoader loader = new ImageLoader(queue, new ImageLoader.ImageCache() {        @Override        public Bitmap getBitmap(String url) {            return null;        }        @Override        public void putBitmap(String url, Bitmap bitmap) {        }    });    //4.构造一个图片下载的监听器    ImageLoader.ImageListener listener = ImageLoader.getImageListener(mImageView, R.drawable.default_icon, R.drawable.error_icon);    //5.下载图片    loader.get(imageURL, listener);}

上面只是一个简单的应用,还没有用到ImageLoader最重要的点,那就是缓存,因为上面的ImageCache是一个空的,完全没有缓存的作用,所以我们还要写一个ImageCache,这就用到了Android提供的LRUCahce,当然也很简单,上代码:

@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) // LruCache 这个类是在Android 3.1出现的所以要加注解来标识一下public class LruBitmapCache extends LruCache<String, Bitmap> implements ImageLoader.ImageCache {    public LruBitmapCache() {        this(getDefaultLruCacheSize());    }    //设置最大内存    public LruBitmapCache(int sizeInMib) {        super(sizeInMib);    }    // 用来计算Bitmap的大小    @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);    }    /**     * 获取默认的缓存大小,为运行时堆内存的最大内存的 1/8。     *     * @return 缓存大小值,以Mib为单位     */    public static int getDefaultLruCacheSize() {        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024 / 1024);        return maxMemory / 8;    }}

我们继承及成LruCache并且实现了ImageCache接口,设置了图片的缓存大小。我使用的时候可以下面这样:

 ImageLoader mLoader= new ImageLoader(queue, new LruBitmapCache());

有没有感觉这样太麻烦了,每次都要写这么一大堆,当我们把ImageCache实现之后,可以把相应的代码抽取出来,做一个单例类,每次使用的时候只需要一样代码就可以实现。具体代码如下:

public class ImageLoaderManager {    private RequestQueue mQueue;    private ImageLoader mLoader;    public static ImageLoaderManager getInstance() {        return ImageLoaderManagerInstance.loaderManager;    }    private ImageLoaderManager() {        //1.请求队列        mQueue = App.getQueue();    }    private static final class ImageLoaderManagerInstance {        final static ImageLoaderManager loaderManager = new ImageLoaderManager();    }    public void load(ImageView view,String imageURL){        //2.使用请求队列和ImageCache构造一个ImageLoader        mLoader = getImageLoader();        //3.构造一个图片下载的监听器        ImageLoader.ImageListener listener = ImageLoader.getImageListener(view, R.drawable.default_icon, R.drawable.error_icon);        //4.下载图片        mLoader.get(imageURL, listener);    }    public ImageLoader getImageLoader() {        if(mLoader == null){            mLoader= new ImageLoader(mQueue, new LruBitmapCache());        }        return mLoader;    }}

当我们可以这样使用:

String imageURL = "http://c.hiphotos.baidu.com/image/pic/item/0dd7912397dda1449fad6f63b6b7d0a20df486be.jpg";ImageLoaderManager.getInstance().load(mImageView,imageURL);

NetworkImageView

在Volley里除了使用 ImageRequestImageloader加载网络图片,还提供了第三种方式,那就是NetworkImageView;它是一个自定义的View,继承自ImageView;它比其它两种方式都好用,具体用法如下:

首先 在布局里面添加NetWorkImageView

 <com.android.volley.toolbox.NetworkImageView     android:id="@+id/networkImageView"     android:layout_width="wrap_content"     android:layout_height="wrap_content"/>

然后在Activity里面获取这个控件

mNetworkImageView = (NetworkImageView) findViewById(R.id.networkImageView);

最后给NetworkImageView设置默认图,失败图,和图片的URL;需要注意的是,在设置图片URL的时候需要用到上面的ImageLoader;代码如下:

    mNetworkImageView.setDefaultImageResId(R.drawable.default_icon);    mNetworkImageView.setErrorImageResId(R.drawable.error_icon);    mNetworkImageView.setImageUrl(imageURL,ImageLoaderManager.getInstance().getImageLoader());

这样就OK了。

在布局里面,没有给NetworkImageView设置具体的宽高,这样不会对图像进行压缩,如果想压缩就给它设置 android:layout_widthandroid:layout_height属性就可以了,它会在内部自动化完成。

0 0
原创粉丝点击