后来到网上查了下资料,发现在最新的Android SDK中,这个类已经被移除了。就是说Google在最新的SDK中不再支持使用HttpClient来访问网络了。这里就告诉我们一个十分重要的道理:在开发项目的时候,我们要尽量的不用或者是少用那些已经过时了(deprecated)的方法了,因为在后来更新的SDK版本中,我们可能就没法使用某些被Google丢弃的封装类了,然后程序就会报错。像我遇到的httpclient这个类就无法使用的情况。还有一点就是我们要时刻关注Google对Android 像是开发工具和SDK的更新情况等,这是作为一名Android 开发人员应该有的修养---目光要在技术的前端。
为什么HttpClient不可以使用了?这段时间里,到底发生了什么事?
原来,之前我们使用的HttpURLConnection和HttpClient的用法还是挺复杂的,而且其中的API多,不易扩展,容易出bug,稍不注意就会写出不少重复代码和error。所以,在2013年Google I/O大会上推出了一个新的网络通信框架——Volley。这套框架主要是用于一些不是很大量但是很频繁的网络访问,对于有大量下载的网络访问,它就表现的不行不行的了,这个是要注意的地方。
下面我们先开始来对volley作一个简单的介绍和简单的使用。
一、下载volley 的jar包。
这个jar包是开源的,网上一搜有大把,这里我提供一个下载的地址:点击打开链接 就可以下载了
二、把volley包导入我们的项目中。
copy到项目的libs目录下,右键--->add as libarary,最后ok。
三、开始使用volley框架。
在这里,我自己写了一个类,主要是用来使用volley几个常用的方法来访问网络,获取数据,以及每个方法的源码解释。
先上效果截图:
以及两个图片加载的方法效果图
然后,直接上代码吧,代码里面都有详细的解释了。
先是布局代码:很简单的一个scrollview包含一个多个控件的linearlayout,因为要显示的内容比较长,所用要scrollview。
<span style="font-size:14px;"><LinearLayout 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:orientation="vertical"
tools:context=".MainActivity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="@+id/ed_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:singleLine="true"
android:text="https://www.baidu.com"
android:textSize="20sp" />
<Button
android:id="@+id/btn_getdate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="URLConnection方式获取网络数据" />
<Button
android:id="@+id/btn_volleyget"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:text="volley-GET方式获取网络数据" />
<Button
android:id="@+id/btn_volleypost"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:text="volley-POST方式获取网络数据" />
<Button
android:layout_marginTop="3dp"
android:id="@+id/btn_volleyJSON_obj"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="volleyJSONobject获取网络object对象数据" />
<Button
android:id="@+id/btn_volleyJSON_arr"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:text="volley-JSONarray获取往array对象数据" />
<Button
android:id="@+id/btn_getimg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:text="volley-ImageLoader加载图片" />
<Button
android:id="@+id/btn_NetworkImageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:text="volley-NetworkImageView加载图片" />
<ImageView
android:id="@+id/img_show1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitCenter" />
<ImageView
android:id="@+id/img_show"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitCenter" />
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/networkImageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp" />
<TextView
android:id="@+id/tv_show"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/hello_world"
android:textSize="20sp" />
</LinearLayout>
</ScrollView>
</LinearLayout></span>
再然后是主要的java代码实现,里面有很详细的用法介绍和源码解释了,大家可以认真看看。
<span style="font-size:14px;">package com.yaojt.com.httptest;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.util.LruCache;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
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.ImageLoader;
import com.android.volley.toolbox.JsonArrayRequest;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.NetworkImageView;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
public class MainActivity extends Activity {
private TextView tv_show;
private Button btn_getdate;
private String URL = "https://www.baidu.com";
private String URL1 = "http://m.weather.com";
private EditText ed_input;
private Button btn_volleyget;
private Button btn_volleypost;
private Button btn_volleyJSONobject, btn_volleyJSONarray;
private Button btn_getimg;
private ImageView img_show, img_show1;
private Button btn_NetworkImageView;
private HttpURLConnection conn;
private RequestQueue requestQueue;
private JsonObjectRequest jsonObjectRequest;
private JsonArrayRequest jsonArrayRequest;
private StringRequest requestPOST;
private StringRequest requestGET;
private NetworkImageView mNetworkImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestQueue = Volley.newRequestQueue(this); //一开始得到一个请求队列,主要是用于对网络请求的派件工作
initViews();
initListener();
}
/**
* 初始化控件
*/
private void initViews(){
tv_show = (TextView) findViewById(R.id.tv_show);
btn_getdate = (Button) findViewById(R.id.btn_getdate);
ed_input = (EditText) findViewById(R.id.ed_input);
btn_volleyget = (Button) findViewById(R.id.btn_volleyget);
btn_volleypost = (Button) findViewById(R.id.btn_volleypost);
btn_volleyJSONobject = (Button) findViewById(R.id.btn_volleyJSON_obj);
btn_volleyJSONarray = (Button) findViewById(R.id.btn_volleyJSON_arr);
btn_getimg = (Button) findViewById(R.id.btn_getimg);
img_show = (ImageView) findViewById(R.id.img_show);
img_show = (ImageView) this.findViewById(R.id.img_show);
mNetworkImageView = (NetworkImageView) findViewById(R.id.networkImageView);
btn_NetworkImageView = (Button) findViewById(R.id.btn_NetworkImageView);
img_show1 = (ImageView) findViewById(R.id.img_show1);
}
/**
* 初始化监听器
*/
private void initListener(){
btn_NetworkImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NetworkImageViewGetImg(); //直接调用此方法,然后再布局中直接显示图片
}
});
btn_getimg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ImageLoaderGetImg();
}
});
btn_volleyJSONarray.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
URL1 = ed_input.getText().toString().trim();
volleyJSONarray();
}
});
btn_volleyJSONobject.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
URL = ed_input.getText().toString().trim();
volleyJSONobject();
}
});
btn_volleypost.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
URL = ed_input.getText().toString().trim();
volleyPOST();
}
});
btn_volleyget.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
URL = ed_input.getText().toString().trim();
volleyGET();
}
});
btn_getdate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
URL = ed_input.getText().toString().trim();
asynctaskLOAD(URL);
}
});
}
/**
* 利用JsonObjectRequest来得到JSONObject对象
*
* Constructor which defaults to <code>GET</code> if <code>jsonRequest</code> is
* <code>null</code>, <code>POST</code> otherwise.
*
* //@see #JsonObjectRequest(int, String, JSONObject, Response.Listener, Response.ErrorListener)
* public JsonObjectRequest(String url, JSONObject jsonRequest, Response.Listener<JSONObject> listener,
Response.ErrorListener errorListener) {
this(jsonRequest == null ? Request.Method.GET : Request.Method.POST, url, jsonRequest, listener, errorListener); //可以看到源码
//如果第二个参数传入的值!= null 的话,它会选择是post方式
}
*/
private void volleyJSONobject() {
String url = "http://pipes.yahooapis.com/pipes/pipe.run?_id=giWz8Vc33BG6rQEQo_NLYQ&_render=json";
jsonObjectRequest = new JsonObjectRequest(url, null, new Response.Listener<JSONObject>() { //这里传入null,会选择是get方式
@Override
public void onResponse(JSONObject response) {
tv_show.setText("利用JsonObjectRequest得到的object对象为:" + response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
tv_show.setText("===>>利用JsonObjectRequest访问网络错误,错误信息为:" + error);
}
});
requestQueue.add(jsonObjectRequest);
}
/**
* 利用JsonArrayRequest得到JSONArray对象
*
* 源码:
* Creates a new request. 创建一个新的请求
*
* //@param url URL to fetch the JSON from
* //@param listener Listener to receive the JSON response
* //@param errorListener Error listener, or null to ignore errors.
*public JsonArrayRequest(String url, Response.Listener<JSONArray> listener, Response.ErrorListener errorListener) {
super(Request.Method.GET, url, null, listener, errorListener); //这里使用的是Request.Method.GET 方式
}
*/
private void volleyJSONarray() {
jsonArrayRequest = new JsonArrayRequest(URL1, new Response.Listener<JSONArray>() { //它这里只有get方式
@Override
public void onResponse(JSONArray response) {
tv_show.setText("利用volley-JsonArrayRequest方式获取的的网络数据为:" + response.toString());
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
//因为我这里没有一个返回jsonarrayrequest的接口,所以这里返回的数据老是提示错误
tv_show.setText("利用volley-JsonArrayRequest方式访问错误,错误信息为:" + error);
}
});
requestQueue.add(jsonArrayRequest); //将请求加入到请求队列中区
}
/**
* 利用StringRequest得到String对象
*
* Creates a new request with the given method. 创建一个给定方式的请求
*
* //@param method the request {@link Request.Method} to use 参数一:请求方式get或者post
* //@param url URL to fetch the string at
* //@param listener Listener to receive the String response
* //@param errorListener Error listener, or null to ignore errors
* public StringRequest(int method, String url, Response.Listener<String> listener,
Response.ErrorListener errorListener) {
super(method, url, errorListener);
mListener = listener;
}
*/
private void volleyPOST() {
requestPOST = new StringRequest(Request.Method.POST, URL, new Response.Listener<String>() { //指定为post方式
@Override
public void onResponse(String s) { //这里指定的是post方法
tv_show.setText("利用volley--POST方式得到的网络数据:" + s);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
tv_show.setText("利用volley--POST方式访问网络错误,错误信息为:" + volleyError.toString());
}
});
requestQueue.add(requestPOST); //最后要记得加入到请求队列中去
}
/**
* 默认利用GET方式得到string对象
* 看下面源码:
*
* Creates a new GET request. 创建一个新的get方式的请求
*
* //@param url URL to fetch the string at
* //@param listener Listener to receive the String response 这个是Response接口类里面的Listener方法
* //@param errorListener Error listener, or null to ignore errors 这个是Response接口类里面的ErrorListener方法
* public StringRequest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {
this(Request.Method.GET, url, listener, errorListener); //这里是默认的get方式
}
*/
private void volleyGET() {
requestGET = new StringRequest(URL, new Response.Listener<String>() { //这个是默认的利用get方式访问网络 看注释源码
@Override
public void onResponse(String s) { //源码中默认的是get的方式
tv_show.setText("利用volley--GET方式得到的网络数据:" + s);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
tv_show.setText("利用volley--GET方式访问网络error,错误信息为:" + volleyError.toString());
}
});
requestQueue.add(requestGET); //最后要记得加入到请求队列中去
}
/**
* 利用AsyncTask异步任务来加载图片
*
* @param url
*/
private void asynctaskLOAD(String url) {
new AsyncTask<String, String, String>() { //new一个匿名异步任务类实例,参数一:传入值;参数二:过程传出值;参数三:结果返回值;
@Override
protected String doInBackground(String... params) {
String str = "";
try {
URL url = new URL(params[0]); //取得第一个参数URL地址
URLConnection connection = url.openConnection(); //打开连接
InputStream in = connection.getInputStream(); //得到输入流
InputStreamReader isr = new InputStreamReader(in, "utf-8"); //将输入流包装成字符流,并指定编码格式
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
str += line;
}
br.close(); //这里要关闭流,是先打开后关闭
isr.close();
in.close();
} catch (IOException e) {
e.printStackTrace();
}
return str; //这里是结果返回值
}
@Override
protected void onPostExecute(String string) { //接收到结果返回值,并作处理
tv_show.setText("利用AsyncTask异步任务方式得到的网络数据:" + string);
}
}.execute(url); //记得要执行,这个异步任务才会执行
}
/**
* 利用ImageLoader来加载网络图片
* getImageListener(ImageView view, int defaultImageResId, int errorImageResId) //这个方法就是传入一个请求队列和一个图片的缓存即可
* 第一个参数:显示图片的ImageView
* 第二个参数:默认显示的图片资源
* 第三个参数:加载错误时显示的图片资源
*
* 我们关键来看看ImageListener getImageListener(final ImageView view,final int defaultImageResId, final int errorImageResId)这个方法是得到
* 一个图片加载的监听器和两个回调函数
* 看到第一个参数的解释:The imageView that the listener is associated with.和监听器关联的img,其实这个是你加载了的图片要显示的位置
* 我们可以直接看到它的关键源码:
* view.setImageResource(errorImageResId); //当错误时显示的图片,第三个参数
* view.setImageBitmap(response.getBitmap()); //成功加载的图片显示
* view.setImageResource(defaultImageResId); //在加载过程中显示的默认图片,代替失败或者是成功前的图片显示
* 所以,我们只要将我们显示图片的控件传进去就可以了
*/
//这里加载一张图片在imgv上显示
public void ImageLoaderGetImg() {
final LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(8); //缓存为8m
//这里new一个缓存空间,也可以使用在最后面一个继承自ImageLoader.ImageCache的类来做,这里就不演示了
ImageLoader imageLoader = new ImageLoader(requestQueue, new ImageLoader.ImageCache() { //传入网络请求队列和图片的缓存对象
@Override
public Bitmap getBitmap(String key) {
return lruCache.get(key);
} //将图片存储起来,下次运行时会优先选择在内存中是否有这个图片的缓存,有则直接读取出来,没有再到网上去取数据
@Override
public void putBitmap(String key, Bitmap bitmap) {
lruCache.put(key, bitmap);
}
});
String url = "http://e.hiphotos.baidu.com/image/pic/item/d0c8a786c9177f3e6bf9623a75cf3bc79f3d5633.jpg";
ImageLoader.ImageListener listener = ImageLoader.getImageListener(img_show, R.drawable.imgv1, R.drawable.imgv2); //传入URL,默认图片和失败图片
imageLoader.get(url, listener); //最后要运行调用get方法,传入url和监听器
//指定图片允许的最大宽度和高度
// imageLoader.get(url,listener, 200, 200);
}
/**
*
* 利用NetworkImageView显示网络图片,这里要在布局中创建一个com.android.volley.toolbox.NetworkImageView控件,看布局代码
* 我们来看下setImageUrl这个方法的执行流程
*
* 方法的解释:给NetworkImageView这个控件设置一个给定URL路径的图片。
* 此方法会立即在缓存中查找有无此图片;有则显示,没有则通过调用NetworkImageView
* 方法显示一个默认加载图片并且去加载此图片。
*
* 在方法内部会调用
* loadImageIfNecessary(false); // The URL has potentially changed. See if we need to load it.
* 我们来走下这个方法:
* 1、先得到此控件的宽高;如果宽高为0,则返回;
* 2、判断传入url是否为空;为空则将请求取消,设置控件的图片为null,并返回;
* 3、判断此控件的前一个请求是否要取消它(前提是有前一个请求),这里有两个情况:一、同一个
* url请求,返回;二、不是同一个url请求,取消前一个请求,然后下一步;
* 4、调用ImageContainer newContainer = ImageLoader.get()方法去加载新的url图片,new一个ImageListener图片监听方法,成功则显示
* 加载的图片,不成功则加载错误显示的图片;(这里面还有一个布尔值参数isInLayoutPass = false
* 重新开新线程去回调onRespose方法,默认是没有调用的);
* 5、最后将控件的mImageContainer更新为新的newContainer ;
*
*/
//此方法是在布局的NetworkImageView控件上加载显示一张图片
private void NetworkImageViewGetImg() {
String imageUrl = "http://f.hiphotos.baidu.com/image/pic/item/c9fcc3cec3fdfc03777a357fd03f8794a5c226f3.jpg";
final LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(8);
ImageLoader.ImageCache imageCache = new ImageLoader.ImageCache() { //创建一个图片缓存实例
@Override
public void putBitmap(String key, Bitmap value) {
lruCache.put(key, value);
}
@Override
public Bitmap getBitmap(String key) {
return lruCache.get(key);
}
};
ImageLoader imageLoader = new ImageLoader(requestQueue, imageCache);
mNetworkImageView.setTag("url");
mNetworkImageView.setImageUrl(imageUrl, imageLoader);
}
/**
* bitmap存储类,继承自ImageLoader.ImageCache。这里没有用到
*/
private class BitmapCache implements ImageLoader.ImageCache {
private LruCache<String, Bitmap> cache;
public BitmapCache() {
cache = new LruCache<String, Bitmap>(8 * 1024 * 1024) { //缓存空间为8m
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight();
}
};
}
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
}
}</span>
以上是volley框架的代码示例,比较长,但是是比较实用的。
总的来讲,volley框架并不会很难懂,因为开发volley框架本来就是让大家的开发过程变得很简练简约。所以学习此框架还是很不错的。
到此为止了,若哪里理解有偏差,请指教!