Android系统中主要提供了两种方式来进行HTTP通信,HttpURLConnection和HttpClient,几乎任何项目的代码中我们都能看到两个类的身影,使用率非常高。不过HttpURLConnection和HttpClient的用法还是有些复杂,Android开发团队也是意识到了有必要将HTTP的通信操作再进行简单化,于是在2013年Google I/O大会上推出了一个新的网络通信框架——Volley。
Volley除了简单易用之外,在性能方面也进行了大幅度调整,它的设计目标适就是适合进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。
Volley下载地址:
git clone (点击打开链接)http://android.googlesource.com/platform/frameworks/volley
这里提供我上传的jar包:http://download.csdn.net/detail/yabaj/9408577
Volley提供的功能:
- JSON,图像等的异步下载;
- 网络请求的排序(scheduling)
- 网络请求的优先级处理
- 缓存
- 多级别取消请求
- 和Activity的生命周期的联动(Activity结束时同时取消所有网络请求)
RequestQueue是一个请求队列对象,它可以缓存所有的HTTP请求,然后按照一定的算法并发地发出这些请求。RequestQueue内部的设计就是非常适合高并发的,因此我们不必为每一次HTTP请求都创建一个RequestQueue对象,这是非常浪费资源的,基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了,而且其中内置了线程不用我们去写。
示例代码:
public class NetworkActivity extends Activity implements OnClickListener{ private RequestQueue queue = null; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_network); Button bt = (Button) findViewById(R.id.bt_volley_stringrequest); bt.setOnClickListener(this); //创建队列 queue = Volley.newRequestQueue(getApplicationContext()); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.bt_volley_stringrequest: // TODO Auto-generated method stub /*String path = "http://192.168.1.100:8080/TestAndroid/testServlet?name=zhangsan&age=23"; StringRequest request = new StringRequest(Request.Method.GET, path, new Listener<String>() { @Override public void onResponse(String arg0) { // TODO Auto-generated method stub String s = null; try { byte temp[]=arg0.getBytes("iso-8859-1"); s = new String(temp,"UTF-8"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } 打印出服务器传过来的数据 Log.e("onResponse", s); } }, new com.android.volley.Response.ErrorListener() { @Override public void onErrorResponse(VolleyError arg0) { // TODO Auto-generated method stub Log.e("错误onErrorResponse", arg0.toString()); } });*/ String path = "http://192.168.1.100:8080/TestAndroid/testServlet"; StringRequest request = new StringRequest(Request.Method.POST, path, new Listener<String>() { @Override public void onResponse(String arg0) { // TODO Auto-generated method stub String s = null; try { byte temp[]=arg0.getBytes("iso-8859-1"); s = new String(temp,"UTF-8"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } Log.e("onResponse", s); } }, new com.android.volley.Response.ErrorListener() { @Override public void onErrorResponse(VolleyError arg0) { // TODO Auto-generated method stub Log.e("错误onErrorResponse", arg0.toString()); } }){ @Override protected Map<String, String> getParams() throws AuthFailureError { // TODO Auto-generated method stub Map<String, String> map = new HashMap<String, String>(); map.put("name", "张三"); map.put("age", "24"); return map; } }; queue.add(request); break; default: break; } } }
get请求结果:
post请求结果:
我们可以看出连接服务器只需一个类StringRequest就解决了问题,是不是很激动。。再看下一个。。
2.JsonRequest
类似于StringRequest,JsonRequest也是继承自Request类的,JsonRequest是一个抽象类。JsonRequest有两个直接的子类JsonObjectRequest和JsonArrayRequest。
示例代码:
这种方式服务器只能向前台传送json格式的数据,(一)的服务器代码需要作如下改动:
/** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); System.out.println("进入get方法"); String name = request.getParameter("name"); String age = request.getParameter("age"); System.out.println("name=" + name + ",age=" + age); PrintWriter writer = response.getWriter(); // writer.write("Get : name,age send 成功"); String json = "{'info':'Get','content':'name,age send 成功'}";//json字符串 writer.write(json); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); System.out.println("进入post方法"); String name = request.getParameter("name"); String age = request.getParameter("age"); System.out.println("name=" + name + ",age=" + age); PrintWriter writer = response.getWriter(); // writer.write("Post : name,age send 成功"); String json = "{'info':'Post','content':'name,age send 成功'}";<span style="font-family: Arial, Helvetica, sans-serif;">//json字符串</span> writer.write(json); }
android端代码:POST请求时,JsonObjectRequest的构造方法参数里不能直接传JsonObject对象进去,因为我使用的apache tomcat服务器只支持传入键值对格式参数的方式(如name='zhangsan'&age=23),而不支持json格式。所以需要重写Request类中的parseNetworkResponse方法,非常麻烦,这种情况下不建议使用。
public class NetworkActivity extends Activity implements OnClickListener{ private RequestQueue queue = null; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_network); Button bt = (Button) findViewById(R.id.bt_volley_jsonrequest); bt.setOnClickListener(this); //创建队列 queue = Volley.newRequestQueue(getApplicationContext()); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.bt_volley_jsonrequest: //get请求 /*String path = "http://192.168.1.100:8080/TestAndroid/testServlet?name=zhangsan&age=23"; //这里是get请求,不用在这里传参,JsonRequest为null JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, path, null, new Listener<JSONObject>() { @Override public void onResponse(JSONObject arg0) { // TODO Auto-generated method stub String s = null; try { byte temp[]=arg0.toString().getBytes("iso-8859-1"); s = new String(temp,"UTF-8"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } 打印出服务器传过来的数据 Log.e("onResponse", s); } }, new com.android.volley.Response.ErrorListener() { @Override public void onErrorResponse(VolleyError arg0) { // TODO Auto-generated method stub Log.e("错误onErrorResponse", arg0.toString()); } });*/ //post请求 String path = "http://192.168.1.100:8080/TestAndroid/testServlet"; Map<String, String> map = new HashMap<String, String>(); map.put("name", "张三"); map.put("age", "24"); NormalPostRequest request = new NormalPostRequest(path, new Listener<JSONObject>() { @Override public void onResponse(JSONObject arg0) { // TODO Auto-generated method stub String s = null; try { byte temp[]=arg0.toString().getBytes("iso-8859-1"); s = new String(temp,"UTF-8"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } 打印出服务器传过来的数据 Log.e("onResponse", s); } }, new com.android.volley.Response.ErrorListener() { @Override public void onErrorResponse(VolleyError arg0) { // TODO Auto-generated method stub Log.e("错误onErrorResponse", arg0.toString()); } }, map); queue.add(request); break; default: break; } } private class NormalPostRequest extends Request<JSONObject> { private Map<String, String> mMap; private Listener<JSONObject> mListener; public NormalPostRequest(String url, Listener<JSONObject> listener,ErrorListener errorListener, Map<String, String> map) { super(Request.Method.POST, url, errorListener); mListener = listener; mMap = map; } //mMap是已经按照前面的方式,设置了参数的实例 @Override protected Map<String, String> getParams() throws AuthFailureError { return mMap; } //此处因为response返回值需要json数据,和JsonObjectRequest类一样即可 @Override protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data,HttpHeaderParser.parseCharset(response.headers)); return Response.success(new JSONObject(jsonString),HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JSONException je) { return Response.error(new ParseError(je)); } } @Override protected void deliverResponse(JSONObject response) { mListener.onResponse(response); } } }
get请求运行结果:
post请求运行结果:
3.ImageRequest
4.ImageLoader用于网络图片加载。
示例代码:
public class NetworkActivity extends Activity implements OnClickListener{ private RequestQueue queue = null; private ImageView imageView = null; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_network); Button bt = (Button) findViewById(R.id.bt_volley_imagerequest); bt.setOnClickListener(this); imageView = (ImageView) findViewById(R.id.my_image); //创建队列 queue = Volley.newRequestQueue(getApplicationContext()); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.bt_volley_imagerequest: //网络上的图片下载地址,也可以换成自己的服务器地址 String path = "http://image.baidu.com/search/down?tn=download&word=download&ie=utf8&fr=detail&url=http%3A%2F%2Fwww.th7.cn%2Ffeizhuliu%2FUploadFiles_2544%2F201010%2F2010100513025822.jpg&thumburl=http%3A%2F%2Fimg5.imgtn.bdimg.com%2Fit%2Fu%3D3866172907%2C1449770762%26fm%3D206%26gp%3D0.jpg"; // 参数解释 // 第一个:图片下载路径 // 第二个:图片请求成功的回调,在这里把返回的Bitmap参数设置到ImageView中 // 第三、四个:指定图片的最大宽度和最大高度,如果指定的网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩,指定成0的话,不管图片多大都不会进行压缩 // 第五个:指定图片的颜色属性,Config.ARGB_8888:最优的颜色,每个图片像素占四个字节;Config.RGB_565:每个图片像素占两个字节 // 第六个:图片请求失败的回调,这里当我们请求失败时在ImageView显示一张默认图片 ImageRequest request = new ImageRequest(path, new Listener<Bitmap>() { @Override public void onResponse(Bitmap bitmap) { // TODO Auto-generated method stub imageView.setImageBitmap(bitmap); } }, 0, 0, Config.RGB_565, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // TODO Auto-generated method stub Log.e("错误回调", error.toString()); } }); queue.add(request); break; default: break; } } }
ImageLoader也可用于图片加载,并且它的内部也是呀ImageRequest来实现的,不过ImageLoader要比ImageRequest更加高效,因为它不仅可以帮我们对图片进行缓存,还可以过滤掉重复的链接,避免重复发送请求。
示例代码:
●●这里是无缓存的代码:
public class NetworkActivity extends Activity implements OnClickListener{ private RequestQueue queue = null; private ImageView imageView = null; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_network); Button bt = (Button) findViewById(R.id.bt_volley_imageloader); bt.setOnClickListener(this); imageView = (ImageView) findViewById(R.id.my_image); //创建队列 queue = Volley.newRequestQueue(getApplicationContext()); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.bt_volley_imageloader: String path = "http://192.168.0.141:8080/TestAndroid/image/pic01.jpg"; //创建ImageLoader加载器 //无缓存 ImageLoader imageLoader = new ImageLoader(queue, new ImageCache() { @Override public void putBitmap(String arg0, Bitmap arg1) { // TODO Auto-generated method stub } @Override public Bitmap getBitmap(String arg0) { // TODO Auto-generated method stub return null; } }); //获取ImageListener监听器对象 ImageListener imageListener = ImageLoader.getImageListener(imageView, R.drawable.bg01, R.drawable.ic_launcher); //访问图片地址 imageLoader.get(path, imageListener, 400, 400); break; default: break; } } }
●●这里是有缓存的代码(需要自己写一个缓存的类,实现ImageCache接口):
public class NetworkActivity extends Activity implements OnClickListener{ private RequestQueue queue = null; private ImageView imageView = null; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_network); Button bt = (Button) findViewById(R.id.bt_volley_imageloader); bt.setOnClickListener(this); imageView = (ImageView) findViewById(R.id.my_image); //创建队列 queue = Volley.newRequestQueue(getApplicationContext()); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.bt_volley_imageloader: String path = "http://192.168.0.141:8080/TestAndroid/image/pic01.jpg"; //创建ImageLoader加载器 //有缓存 ImageLoader imageLoader = new ImageLoader(queue, new MyImageCache()); //获取ImageListener监听器对象 ImageListener imageListener = ImageLoader.getImageListener(imageView, R.drawable.bg01, R.drawable.ic_launcher); //访问图片地址 imageLoader.get(path, imageListener, 400, 400); break; default: break; } } /* * 这里是二级缓存,保存在内存里,程序关闭自动清空 */ private class MyImageCache implements ImageCache{ private LruCache<String, Bitmap> lruCache = null; public MyImageCache() { super(); int maxSize = 10 * 1024 * 1024; //创建缓存容器,缓存Bitmap this.lruCache = new LruCache<String, Bitmap>(maxSize){ /* * 计算每次缓存一个bitmap的大小 * @see android.util.LruCache#sizeOf(java.lang.Object, java.lang.Object) */ @Override protected int sizeOf(String key, Bitmap value) { // TODO Auto-generated method stub //计算每个位图的字节大小 return value.getRowBytes() * value.getHeight(); } }; } /* * 从缓存中取出bitmap对象 * @see com.android.volley.toolbox.ImageLoader.ImageCache#getBitmap(java.lang.String) */ @Override public Bitmap getBitmap(String arg0) { // TODO Auto-generated method stub Log.e("getBitmap---arg0", arg0); return lruCache.get(arg0); } /* * 将下载下来的位图对象放入缓存中 * @see com.android.volley.toolbox.ImageLoader.ImageCache#putBitmap(java.lang.String, android.graphics.Bitmap) */ @Override public void putBitmap(String arg0, Bitmap bitmap) { // TODO Auto-generated method stub lruCache.put(arg0, bitmap); } } }
5.NetworkImageView
这是第三种加载网络图片的方式,NetworkImageView是一个自定义控件,它是继承自ImageView的,具备ImageView控件所有功能,且在原生的基础上加入了加载网络图片的功能。这种方法比前两种加载图片的方式更加简单。
●●添加布局文件:
●●示例代码:<com.android.volley.toolbox.NetworkImageView android:layout_width="400dp" android:layout_height="400dp" android:scaleType="fitXY" android:background="@android:color/holo_blue_light" android:id="@+id/my_network_image">
public class NetworkActivity extends Activity implements OnClickListener{ private RequestQueue queue = null; private NetworkImageView networkImageView = null; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_network); Button bt1 = (Button) findViewById(R.id.bt_volley_imagerequest); bt1.setOnClickListener(this); networkImageView = (NetworkImageView) findViewById(R.id.my_network_image); //创建队列 queue = Volley.newRequestQueue(getApplicationContext()); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.bt_volley_networkimageview: String path = "http://image.baidu.com/search/down?tn=download&ipn=dwnl&word=download&ie=utf8&fr=result&url=http%3A%2F%2Fa.hiphotos.baidu.com%2Fzhidao%2Fpic%2Fitem%2Fc2cec3fdfc039245c62b6f018594a4c27d1e2525.jpg&thumburl=http%3A%2F%2Fimg1.imgtn.bdimg.com%2Fit%2Fu%3D2872232886%2C2936175233%26fm%3D206%26gp%3D0.jpg"; networkImageView.setDefaultImageResId(R.drawable.bg01); networkImageView.setErrorImageResId(R.drawable.ic_launcher); ImageLoader imageLoader = new ImageLoader(queue, new MyImageCache()); //下载图片 networkImageView.setImageUrl(path, imageLoader); break; default: break; } } /* * 这里是二级缓存,保存在内存里,程序关闭自动清空 */ private class MyImageCache implements ImageCache{ private LruCache<String, Bitmap> lruCache = null; public MyImageCache() { super(); int maxSize = 10 * 1024 * 1024; //创建缓存容器,缓存Bitmap this.lruCache = new LruCache<String, Bitmap>(maxSize){ /* * 计算每次缓存一个bitmap的大小 * @see android.util.LruCache#sizeOf(java.lang.Object, java.lang.Object) */ @Override protected int sizeOf(String key, Bitmap value) { // TODO Auto-generated method stub //计算每个位图的字节大小 return value.getRowBytes() * value.getHeight(); } }; } /* * 从缓存中取出bitmap对象 * @see com.android.volley.toolbox.ImageLoader.ImageCache#getBitmap(java.lang.String) */ @Override public Bitmap getBitmap(String arg0) { // TODO Auto-generated method stub Log.e("getBitmap---arg0", arg0); return lruCache.get(arg0); } /* * 将下载下来的位图对象放入缓存中 * @see com.android.volley.toolbox.ImageLoader.ImageCache#putBitmap(java.lang.String, android.graphics.Bitmap) */ @Override public void putBitmap(String arg0, Bitmap bitmap) { // TODO Auto-generated method stub lruCache.put(arg0, bitmap); } } }