`
810364804
  • 浏览: 808188 次
文章分类
社区版块
存档分类
最新评论

Android_开源框架_Volley实例

 
阅读更多

由于博主的水平有限,如有误,请您帮助指正,共同学习,共同进步!
供初学者更好的理解和管理Volley!


1.自定义相关类


Android_开源框架_Volley(Google IO 2013)源代码及内部实现过程分析一文中,简单概述了Volley框架内部实现过程。如想理解彻底应该熟悉android多线程通信机制(Android_Thread多线程_Handler,Message,Looper,MessageQueue多线程和特殊UI更新一文) ,JDK1.5提供的java.util.concurrent相关并发库和http访问网络(Android_HttpURLConnection_Get和Post请求[该框架使用]/Android_HttpClient_get请求post表单提交上传一文)及图片缓存(Android_图片的三级缓存一文)相关知识

https://android.googlesource.com/platform/frameworks/volley

(1).封装MyVolley类

在使用Volley之前,应该先进行初始化(可以自定义Application或者在SplashActivity中完成初始化),仅对外提供RequestQueue(添加request)和ImageLoader(下载图片)get方法!

/**
 * MyVolley.java
 * @see http://blog.csdn.net/zimo2013
 * @author zimo2013
 * 
 */
public class MyVolley {
	private static final String TAG = "MyVolley";

	private static MyVolley instance;
	private static RequestQueue mRequestQueue;
	private static ImageLoader mImageLoader;
	private final static int RATE = 8; // 默认分配最大空间的几分之一

	private MyVolley(Context context) {
		mRequestQueue = Volley.newRequestQueue(context);

		// 确定在LruCache中,分配缓存空间大小,默认程序分配最大空间的 1/8
		ActivityManager manager = (ActivityManager) context
				.getSystemService(Context.ACTIVITY_SERVICE);
		int maxSize = manager.getMemoryClass() / RATE; // 比如 64M/8,单位为M

		// BitmapLruCache自定义缓存class,android本身支持二级缓存,在BitmapLruCache封装一个软引用缓存
		mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache(
				1024 * 1024 * maxSize));

		Log.i(TAG, "MyVolley初始化完成");
	}

	/**
	 * 初始化Volley相关对象,在使用Volley前应该完成初始化
	 * 
	 * @param context
	 */
	public static void init(Context context) {
		if (instance == null) {
			instance = new MyVolley(context);
		}
	}

	/**
	 * 得到请求队列对象
	 * 
	 * @return
	 */
	private static RequestQueue getRequestQueue() {
		throwIfNotInit();
		return mRequestQueue;
	}

	/**
	 * 得到ImageLoader对象
	 * 
	 * @return
	 */
	public static ImageLoader getImageLoader() {
		throwIfNotInit();
		return mImageLoader;
	}

	public static void addRequest(Request<?> request) {
		getRequestQueue().add(request);
	}

	public static void getImage(String requestUrl, ImageView imageView) {
		getImage(requestUrl, imageView, 0, 0);
	}

	public static void getImage(String requestUrl, ImageView imageView,
			int defaultImageResId, int errorImageResId) {
		getImage(requestUrl, imageView, defaultImageResId, errorImageResId, 0,
				0);
	}

	public static void getImage(String requestUrl, ImageView imageView,
			int defaultImageResId, int errorImageResId, int maxWidth,
			int maxHeight) {
		imageView.setTag(requestUrl);
		getImageLoader().get(requestUrl, ImageListenerFactory.getImageListener(
				imageView, defaultImageResId, errorImageResId), maxWidth,
				maxHeight);
	}

	/**
	 * 检查是否完成初始化
	 */
	private static void throwIfNotInit() {
		if (instance == null) {// 尚未初始化
			throw new IllegalStateException("MyVolley尚未初始化,在使用前应该执行init()");
		}
	}
}

(2).图片的三级缓存相关类

/**
 * LruCache缓存管理类,该类实现了ImageCache接口,并实现了LruCache
 * 一旦bitmap对象从LruCache中被挤出,将会被放置在BitmapSoftRefCache中,再配合该框架本身支持的硬盘缓存,可以完成图片三级缓存
 * 
 * BitmapLruCache.java
 * @author zimo2013
 * @see http://blog.csdn.net/zimo2013
 * 
 */
public class BitmapLruCache extends LruCache<String, Bitmap> implements ImageCache {
	private static final String TAG = "BitmapLruCache";

	private BitmapSoftRefCache softRefCache;

	public BitmapLruCache(int maxSize) {
		super(maxSize);
		softRefCache = new BitmapSoftRefCache();
	}

	@Override
	protected int sizeOf(String key, Bitmap value) {
		return value.getRowBytes() * value.getHeight();
	}

	@Override
	protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
		if (evicted) {
			LogUtil.i(TAG, "空间已满,缓存图片被挤出:" + key);
			// 将被挤出的bitmap对象,添加至软引用BitmapSoftRefCache
			softRefCache.putBitmap(key, oldValue);
		}
	}

	/**
	 * 得到缓存对象
	 */
	@Override
	public Bitmap getBitmap(String url) {
		Bitmap bitmap = get(url);
		// 如果bitmap为null,尝试从软引用缓存中查找
		if (bitmap == null) {
			bitmap = softRefCache.getBitmap(url);
		} else {
			LogUtil.i(TAG, "LruCache命中:" + url);
		}
		return bitmap;
	}

	/**
	 * 添加缓存对象
	 */
	@Override
	public void putBitmap(String url, Bitmap bitmap) {
		put(url, bitmap);
	}

}
/**
 * 软引用缓存管理类
 * 
 * BitmapSoftRefCache.java
 * @author zimo2013
 * @see http://blog.csdn.net/zimo2013
 *
 */
public class BitmapSoftRefCache implements ImageCache{
	private static final String TAG = "BitmapSoftRefCache";
	
	private LinkedHashMap<String, SoftReference<Bitmap>> map;
	public BitmapSoftRefCache() {
		map = new LinkedHashMap<String, SoftReference<Bitmap>>();
	}

	/**
	 * 从软引用集合中得到Bitmap对象
	 */
	@Override
	public Bitmap getBitmap(String url) {
		Bitmap bitmap = null;
		SoftReference<Bitmap> softRef = map.get(url);
		if(softRef != null){
			bitmap = softRef.get();
			if(bitmap == null){
				map.remove(url); //从map中移除
				LogUtil.w(TAG, url+"对象已经被GC回收");
			}else{
				LogUtil.i(TAG, "命中"+url);
			}
		}
		return bitmap;
	}

	/**
	 * 从软引用集合中添加bitmap对象
	 */
	@Override
	public void putBitmap(String url, Bitmap bitmap) {
		SoftReference<Bitmap> softRef = new SoftReference<Bitmap>(bitmap);
		map.put(url, softRef);
	}

}

(3).图片错位

关于使用该框架造成图片错位问题,App使用了ImageLoader下载图片,当ListView滚动很快时,还是会发生错位!记得听别人提起过,使用该框架可以避免图片错位,但是结果还是会发生错位,查看源码并没有找到相关避免错位的措施,不知道是不是自己的使用方法不对,如您知晓,麻烦告知博主一下~

这里通过覆写ImageListener方法,通过ImageView为其指定Tag标签,防止图片错位,即比对下载完图片的ImageUrl和当前该ImageView的Tag是否相等~

public class ImageListenerFactory{
	
	public static ImageListener getImageListener(final ImageView view,
            final int defaultImageResId, final int errorImageResId) {
        return new ImageListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                if (errorImageResId != 0) {
                    view.setImageResource(errorImageResId);
                }
            }

            @Override
            public void onResponse(ImageContainer response, boolean isImmediate) {
                if (response.getBitmap() != null) {
                	
                    if(view.getTag().toString() == response.getRequestUrl()){
                    	view.setImageBitmap(response.getBitmap());
                    }else{
                    	LogUtil.i(TAG, "图片错位");
                    }
                } else if (defaultImageResId != 0) {
                    view.setImageResource(defaultImageResId);
                }
            }
        };
    }
}

2.网络请求Request

(1).StringRequest

public void testStringRequest(){
	String url = "http://www.baidu.com";
	//如果出现乱码,应该修改StringRequest的parseNetworkResponse()方法,指定byte[]-->String 编码
	MyVolley.getRequestQueue().add(new StringRequest(url, new Response.Listener<String>() {

		@Override
		public void onResponse(String response) {
			System.out.println("response:"+response);
		}
	}, new Response.ErrorListener() {

		@Override
		public void onErrorResponse(VolleyError error) {
			
		}
	}));
}

(2).JsonObjectRequest

public void testJsonObjectRequest(){
	String url = "http://api.mobile.meituan.com/group/v1/deal/new-cate-list/android/4.1?cityId=1";
	//如果出现乱码,应该修改StringRequest的parseNetworkResponse()方法,指定byte[]-->String 编码
	MyVolley.getRequestQueue().add(
			new JsonObjectRequest(url,
					null, 
					new Response.Listener<JSONObject>() {

						@Override
						public void onResponse(JSONObject response) {
							//该JSONObject为android系统提供的,如果希望得到一个已经解析完的对象,可以继承JsonRequest
							
							//根据response,解析数据
							try {
								System.out.println(response.get("stid"));
							} catch (JSONException e) {
								e.printStackTrace();
							}
						}
					},new Response.ErrorListener() {

						@Override
						public void onErrorResponse(VolleyError error) {
							System.out.println(error);
						}
					})
			);
}

(3).自定义Request(Json解析)

/**
 * MyJsonRequest.java
 * 
 * @author zimo2013
 */
public class MyJsonListRequest<T> extends JsonRequest<T> {
	private Gson gson;
	private Class<T> clazz;
	private String mKey;

	/**
	 * GET请求方式,直接将json字符串解析为 对应的clazz对象
	 * 
	 * @param url
	 *            请求url
	 * @param clazz
	 *            解析的class字节码
	 * @param listener
	 *            请求成功监听器
	 * @param errorListener
	 *            请求失败监听器
	 */
	public MyJsonListRequest(String url, Class<T> clazz, Listener<T> listener,
			ErrorListener errorListener) {
		this(url, null, clazz, listener, errorListener);
	}

	/**
	 * GET请求方式,将json中的key对应的value解析为 对应的clazz对象
	 * 
	 * @param url
	 *            请求url
	 * @param key
	 *            取得指定的key,<b>NOTE:</b>只支持 root-key,所有子key均错误
	 * @param clazz
	 *            解析的class字节码
	 * @param listener
	 *            请求成功监听器
	 * @param errorListener
	 *            请求失败监听器
	 */
	public MyJsonListRequest(String url, String key, Class<T> clazz,
			Listener<T> listener, ErrorListener errorListener) {
		this(Method.GET, url, null, key, clazz, listener, errorListener);
	}

	/**
	 * 
	 * @param method
	 *            请求方法 Use {@link com.android.volley.Request.Method}.
	 * @param url
	 * @param requestBody
	 *            如果是POST请求,可以提交form表单字符串,比如 name=zhangsan&age=20
	 * @param key
	 *            取得指定的key,<b>NOTE:</b>只支持 root-key,所有子key均错误
	 * @param clazz
	 *            解析的class字节码
	 * @param listener
	 *            请求成功监听器
	 * @param errorListener
	 *            请求失败监听器
	 */
	public MyJsonListRequest(int method, String url, String requestBody,
			String key, Class<T> clazz, Listener<T> listener,
			ErrorListener errorListener) {
		super(method, url, null, listener, errorListener);

		this.clazz = clazz;
		mKey = key;
		gson = new Gson();

	}

	@Override
	protected Response<T> parseNetworkResponse(NetworkResponse response) {
		try {
			String json = new String(response.data,
					HttpHeaderParser.parseCharset(response.headers));
			T t = null;
			if(mKey == null){
				t = gson.fromJson(json, clazz);
			}else{
				JsonObject jsonObject = gson.fromJson(json, JsonObject.class);
				t = gson.fromJson(jsonObject.get(mKey), clazz);
			}
			return Response.success(t,
					HttpHeaderParser.parseCacheHeaders(response));
		} catch (UnsupportedEncodingException e) {
			return Response.error(new ParseError(e));
		} catch (JsonSyntaxException e) {
			return Response.error(new ParseError(e));
		}
	}
}
public void testCustomRequest(){
	String urlString = "http://192.168.117.120:8080/news/json.html";
	MyJsonRequest<NewsInfo> request = new MyJsonRequest<NewsInfo>(urlString, NewsInfo.class, new Listener<NewsInfo>() {

		@Override
		public void onResponse(NewsInfo response) {
			System.out.println(response.getClass());
			System.out.println(response);
		}
	}, null);
	MyVolley.getRequestQueue().add(request);
}

(4).POST表单提交

public void testRequestByPost(){
	String urlString = "http://192.168.43.240:8080/news/servlet/Post";
	StringRequest request = new StringRequest(Method.POST, urlString, new Listener<String>() {

		@Override
		public void onResponse(String response) {
			
		}
	}, new ErrorListener() {

		@Override
		public void onErrorResponse(VolleyError error) {
			
		}
	}){
		//覆写getBody()方法提交表单数据
		@Override
		public byte[] getBody() {
			return "name=zhangsan&age=15".getBytes();
		}
	};
	MyVolley.getRequestQueue().add(request);
}

(5).ImageLoader异步加载图片(防错位)

public void testImageLoader(){
	MyVolley.getImageLoader().get(imgUrl, 
			//ImageListenerFactory为自定义类,封装后即可获取图片资源,完成UI更新
			ImageListenerFactory.getImageListener(//参考ImageLoader.getImageListener()
					imageView, 		// ImageView对象
					R.drawable.ic_launcher, // 默认Image,如果不设应置为0
					R.drawable.ic_launcher)); // 错误Image,如果不设应置为0
}

分享到:
评论

相关推荐

    volley网络编程开源框架的demo

    本教程将通过一个简单的示例来解释如何利用Volley框架进行网络编程,实现Android客户端与服务器之间的数据交换。 首先,我们要了解Volley的核心组件。Volley包含以下关键部分: 1. RequestQueue:这是Volley的核心...

    Android_上百实例源码分析以及开源分析_集合打包1

    这可能包括Android SDK中的关键类和方法解析,如Activity、Intent、BroadcastReceiver、Service、ContentProvider等核心组件的源码阅读,以及Android框架层的一些重要库如AndroidX、Volley、Retrofit、OkHttp等的...

    Android_上百实例源码分析以及开源分析_集合打包5

    这个压缩包"Android_上百实例源码分析以及开源分析_集合打包5"显然包含了大量关于Android编程的实例源码和开源项目的分析资料,旨在帮助开发者拓宽视野,增强实战经验。下面我们将详细探讨其中可能涵盖的知识点。 1...

    Android_JSON数据解析

    总结,Android中解析JSON数据涉及的关键知识点包括JSON的基本结构、Gson库的使用、JSONObject和JSONArray的操作、Volley库的网络请求以及Retrofit框架的使用。这些工具和技术使得Android开发者能够高效地处理服务器...

    Android+上百实例源码分析以及开源分析+集合打包9

    本资源"Android+上百实例源码分析以及开源分析+集合打包9"提供了一系列的实战案例和源代码,帮助开发者深入理解Android开发的核心概念,并提升实际操作技能。下面我们将逐一解析这些实例及其涉及的关键知识点。 1. ...

    【06】开源框架.7z

    开源框架在IT行业中扮演着至关重要的角色,尤其是在安卓开发领域。开源框架的广泛使用促进了技术创新,...这个“【06】开源框架”压缩包很可能包含了一些实例、教程或者项目源码,是学习和理解安卓开源框架的好材料。

    android 异步操作框架

    Android提供了多种异步处理框架,其中一个被广泛使用的开源框架是“android-async-http”,它是一个轻量级、高性能的网络库,非常适合进行HTTP请求。 **Android异步操作的重要性** 在Android系统中,主线程负责处理...

    安卓多个开源框架的应用

    本资源包包含了多个开源框架的应用实例,是安卓开发者深入理解和学习的宝贵资料。 首先,我们来看"Libraries for developersV3.39.apk"。这个应用可能是一个集成各种开发库的演示平台,它可能涵盖了网络请求库如...

    volley框架的二次封装

    Volley是一个由Google开发的Android网络库,设计用于高效地处理网络请求,特别是对于移动设备。它的主要目标是简化网络编程,提供一个低延迟、高响应的网络请求库。本项目是对Volley进行了二次封装,增加了更多的...

    50款Android studio项目源码.zip

    10. **依赖注入**:Dagger2或Hilt等依赖注入框架的运用,让代码更模块化,易于维护。 11. **测试与调试**:源码中可能包含单元测试和UI测试,让开发者学习如何编写和执行测试用例,提升代码质量。 通过以上分析,...

    android核心技术与实例详解》电子书与源码

    《Android核心技术与实例详解》是一本专为Android开发者设计的深度学习资料,涵盖了Android平台的基础概念、核心组件以及实际开发中的各种技术问题。通过阅读这本书,开发者可以深入了解Android系统的架构和工作原理...

    安卓巴士总结了近百个Android优秀开源项.zip

    "安卓巴士总结了近百个Android优秀开源项.zip"这个压缩包文件,显然是一个汇聚了众多高质量Android开源项目的集合,对于Android开发者来说,这是一个不可多得的学习资源库。 首先,我们要理解什么是开源项目。开源...

    Android应用源码-Android安卓设计实例源代码43个合集.zip

    这个压缩包文件“Android应用源码-Android安卓设计实例源代码43个合集.zip”包含了一组丰富的Android应用程序源代码实例,对于Android开发者来说,这是一份极具价值的学习资源。这些实例涵盖了Android开发中的各种...

    android和webservice交互的实例

    Android作为一个开源的移动操作系统,广泛应用于智能手机和平板电脑。而Web Service则是一种基于HTTP协议的远程调用技术,能够实现不同平台间的数据交换。本实例将深入探讨如何在Android应用中与Web Service进行通信...

    android 社区源码(开源中国)

    总之,开源中国社区的Android源码是一个全面的Android应用开发实例,涵盖了用户交互、数据处理、网络通信、性能优化等多个方面,对于开发者来说,深入研究这个源码,无疑能提升对Android开发的理解和技能。...

    Volley上传图片(单多图)

    在Volley中,`MultipartRequest`并不是内置的类,但我们可以自己实现或者使用开源的扩展。例如,`TestMultipartRequest-master`这个项目可能提供了这样的实现。通常,`MultipartRequest`需要继承自`Request`,并...

    安卓巴士总结了近百个Android优秀开源项.doc.zip

    文档“安卓巴士总结了近百个Android优秀开源项.doc”是一个包含丰富Android开发资源的压缩包,其中列举了许多高质量的Android开源项目。这些项目通常由全球的开发者社区维护,旨在提供学习、参考和实际开发中的解决...

    Android视频软件开源代码

    【Android视频软件开源代码】是针对移动设备,特别是Android手机的开源项目,它允许开发者深入理解视频播放软件的实现机制,并能在此基础上进行二次开发或自定义功能。这个开源项目为学习Android应用开发,尤其是...

    android中文开发实例教程

    Android开发是全球范围内广泛使用的移动应用开发平台,尤其在中国,由于其开源、灵活的特性,吸引了大量的开发者参与其中。本教程是针对中文开发者设计的最新版指南,旨在帮助初学者和有经验的开发者进一步提升在...

Global site tag (gtag.js) - Google Analytics