大家知道Google支持和发布的Android移动操作系统,主要是为了使其迅速占领移动互联网的市场份额,所谓移动互联网当然也是互联网了,凡是涉及互联网的任何软件任何程序都少不了联网模块的开发,诚然Android联网开发也是我们开发中至关重要的一部分,那么Android是怎么样进行联网操作的呢?这篇博客就简单的介绍一下Android常用的联网方式、判断网络连接状态以及volley框架、AsyncHttpClient框架的使用
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm == null) {
} else {
//如果仅仅是用来判断网络连接
//则可以使用 cm.getActiveNetworkInfo().isAvailable();
NetworkInfo[] info = cm.getAllNetworkInfo();
if (info != null) {
for (int i = 0; i < info.length; i++) {
if (info[i].getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
}
return false;
}
public static boolean isGpsEnabled(Context context) {
LocationManager lm = ((LocationManager) context
.getSystemService(Context.LOCATION_SERVICE));
List accessibleProviders = lm.getProviders(true);
return accessibleProviders != null && accessibleProviders.size() > 0;
}
public static boolean isWifiEnabled(Context context) {
ConnectivityManager mgrConn = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
TelephonyManager mgrTel = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
return ((mgrConn.getActiveNetworkInfo() != null && mgrConn
.getActiveNetworkInfo().getState() == NetworkInfo.State.CONNECTED) || mgrTel
.getNetworkType() == TelephonyManager.NETWORK_TYPE_UMTS);
}
public static boolean is3rd(Context context) {
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkINfo = cm.getActiveNetworkInfo();
if (networkINfo != null
&& networkINfo.getType() == ConnectivityManager.TYPE_MOBILE) {
return true;
}
return false;
}
public static boolean isWifi(Context context) {
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkINfo = cm.getActiveNetworkInfo();
if (networkINfo != null
&& networkINfo.getType() == ConnectivityManager.TYPE_WIFI) {
return true;
}
return false;
}
现在就简单的介绍一下Android常用的联网方式,包括JDK支持的HttpUrlConnection,Apache支持的HttpClient,以及开源的一些联网框架(譬如AsyncHttpClient)的介绍。本篇博客只讲实现过程和方式,不讲解原理,否则原理用文字很难以讲清,其实我们知道怎么去用,就可以解决一些基本开发需要了。
绝大多数的Android应用联网都是基于Http协议的,也有很少是基于Socket的,我们这里主要讲解基于Http协议的联网方式。讲解实例是建立在一个模拟的登录小模块中进行,登录请求数据仅仅只有username和password两个简单字段。
HttpUrlConnection是JDK里提供的联网API,我们知道Android SDK是基于Java的,所以当然优先考虑HttpUrlConnection这种最原始最基本的API,其实大多数开源的联网框架基本上也是基于JDK的HttpUrlConnection进行的封装罢了,掌握HttpUrlConnection需要以下几个步骤:
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(GET);
conn.setConnectTimeout(5000);
conn.setRequestProperty(User-Agent, Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0));
int code = conn.getResponseCode();
InputStream is = conn.getInputStream();
public class StreamTools {
/**
* 将输入流转换成字符串
*
* @param is
* 从网络获取的输入流
* @return
*/
public static String streamToString(InputStream is) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
baos.close();
is.close();
byte[] byteArray = baos.toByteArray();
return new String(byteArray);
} catch (Exception e) {
Log.e(tag, e.toString());
return null;
}
}
}
HttpUrlConnection发送GET请求
/**
* 通过HttpUrlConnection发送GET请求
*
* @param username
* @param password
* @return
*/
public static String loginByGet(String username, String password) {
String path = http://192.168.0.107:8080/WebTest/LoginServerlet?username= + username + &password= + password;
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod(GET);
int code = conn.getResponseCode();
if (code == 200) {
InputStream is = conn.getInputStream(); // 字节流转换成字符串
return StreamTools.streamToString(is);
} else {
return 网络访问失败;
}
} catch (Exception e) {
e.printStackTrace();
return 网络访问失败;
}
}
HttpUrlConnection发送POST请求
/**
* 通过HttpUrlConnection发送POST请求
*
* @param username
* @param password
* @return
*/
public static String loginByPost(String username, String password) {
String path = http://192.168.0.107:8080/WebTest/LoginServerlet;
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod(POST);
conn.setRequestProperty(Content-Type, application/x-www-form-urlencoded);
String data = username= + username + &password= + password;
conn.setRequestProperty(Content-Length, data.length() + );
// POST方式,其实就是浏览器把数据写给服务器
conn.setDoOutput(true); // 设置可输出流
OutputStream os = conn.getOutputStream(); // 获取输出流
os.write(data.getBytes()); // 将数据写给服务器
int code = conn.getResponseCode();
if (code == 200) {
InputStream is = conn.getInputStream();
return StreamTools.streamToString(is);
} else {
return 网络访问失败;
}
} catch (Exception e) {
e.printStackTrace();
return 网络访问失败;
}
}
HttpClient是开源组织Apache提供的Java请求网络框架,其最早是为了方便Java服务器开发而诞生的,是对JDK中的HttpUrlConnection各API进行了封装和简化,提高了性能并且降低了调用API的繁琐。
Android因此也引进了这个联网框架,我们再不需要导入任何jar或者类库就可以直接使用,值得注意的是Android官方已经宣布不建议使用HttpClient了,我们再开发的时候尽量少用吧,但是用了也无妨!
1, 创建HttpClient对象
2,创建HttpGet对象,指定请求地址(带参数)
3,使用HttpClient的execute(),方法执行HttpGet请求,得到HttpResponse对象
4,调用HttpResponse的getStatusLine().getStatusCode()方法得到响应码
5,调用的HttpResponse的getEntity().getContent()得到输入流,获取服务端写回的数据
/**
* 通过HttpClient发送GET请求
*
* @param username
* @param password
* @return
*/
public static String loginByHttpClientGet(String username, String password) {
String path = http://192.168.0.107:8080/WebTest/LoginServerlet?username=
+ username + &password= + password;
HttpClient client = new DefaultHttpClient(); // 开启网络访问客户端
HttpGet httpGet = new HttpGet(path); // 包装一个GET请求
try {
HttpResponse response = client.execute(httpGet); // 客户端执行请求
int code = response.getStatusLine().getStatusCode(); // 获取响应码
if (code == 200) {
InputStream is = response.getEntity().getContent(); // 获取实体内容
String result = StreamTools.streamToString(is); // 字节流转字符串
return result;
} else {
return 网络访问失败;
}
} catch (Exception e) {
e.printStackTrace();
return 网络访问失败;
}
}
1,创建HttpClient对象
2,创建HttpPost对象,指定请求地址
3,创建List,用来装载参数
4,调用HttpPost对象的setEntity()方法,装入一个UrlEncodedFormEntity对象,携带之前封装好的参数
5,使用HttpClient的execute()方法执行HttpPost请求,得到HttpResponse对象
6, 调用HttpResponse的getStatusLine().getStatusCode()方法得到响应码
7, 调用的HttpResponse的getEntity().getContent()得到输入流,获取服务端写回的数据
/**
* 通过HttpClient发送POST请求
*
* @param username
* @param password
* @return
*/
public static String loginByHttpClientPOST(String username, String password) {
String path = http://192.168.0.107:8080/WebTest/LoginServerlet;
try {
HttpClient client = new DefaultHttpClient(); // 建立一个客户端
HttpPost httpPost = new HttpPost(path); // 包装POST请求
// 设置发送的实体参数
List parameters = new ArrayList();
parameters.add(new BasicNameValuePair(username, username));
parameters.add(new BasicNameValuePair(password, password));
httpPost.setEntity(new UrlEncodedFormEntity(parameters, UTF-8));
HttpResponse response = client.execute(httpPost); // 执行POST请求
int code = response.getStatusLine().getStatusCode();
if (code == 200) {
InputStream is = response.getEntity().getContent();
String result = StreamTools.streamToString(is);
return result;
} else {
return 网络访问失败;
}
} catch (Exception e) {
e.printStackTrace();
return 访问网络失败;
}
}
除了上述Android官方推荐的联网框架以外,在开源世界里关于联网框架真是太多太多了,例如afinal,xutils等等,都是一些开源大牛自己封装的联网框架,并且在GitHub开源社区中可以下载到,其实类似的开源联网框架基本上也是基于HttpUrlConnection的进一步封装,大大提高了性能,同时更加简化了使用方法,这里先介绍AsyncHttpClient的一些使用方法。 AsyncHttpClient是一个非常优秀的联网框架,不仅支持所有Http请求的方式,而且还支持文件的上传和下载,要知道用HttpUrlConnection写一个文件上传和下载健全功能是很需要花费一定时间和精力的,因为请求头实在是太多了,稍有不慎就会写错。但是AsyncHttpClient已经封装好了这些“麻烦”,我们只需要下载到AsyncHttpClient的jar包或者源码导入项目中,Http,上传,下载等等,只需要几个简单的api即可搞定。 AsyncHttpClient的GitHub主页:https://github.com/AsyncHttpClient/async-http-client/
1,将下载好的源码拷贝到src目录下
2,创建一个AsyncHttpClient的对象
3,调用该类的get方法发送GET请求,传入请求资源地址URL,创建AsyncHttpResponseHandler对象
4,重写AsyncHttpResponseHandler下的两个方法,onSuccess和onFailure方法
/**
* 通过AsyncHttpClient发送GET请求
*/
public void loginByAsyncHttpGet() {
String path = http://192.168.0.107:8080/WebTest/LoginServerlet?username=zhangsan&password=123;
AsyncHttpClient client = new AsyncHttpClient();
client.get(path, new AsyncHttpResponseHandler() {
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2,
Throwable arg3) {
// TODO Auto-generated method stub
Log.i(TAG, 请求失败: + new String(arg2));
}
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
// TODO Auto-generated method stub
Log.i(TAG, 请求成功: + new String(arg2));
}
});
}
1,将下载好的源码拷贝到src目录下
2,创建一个AsyncHttpClient的对象
3,创建请求参数,RequestParams对象
4,调用该类的post方法发POST,传入请求资源地址URL,请求参数RequestParams,创建AsyncHttpResponseHandler对象
5,重写AsyncHttpResponseHandler下的两个方法,onSuccess和onFailure方法
/**
* 通过AsyncHttpClient发送POST请求
*/
public void loginByAsyncHttpPost() {
String path = http://192.168.0.107:8080/WebTest/LoginServerlet;
AsyncHttpClient client = new AsyncHttpClient();
RequestParams params = new RequestParams();
params.put(username, zhangsan);
params.put(password, 123);
client.post(path, params, new AsyncHttpResponseHandler() {
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2,
Throwable arg3) {
// TODO Auto-generated method stub
Log.i(TAG, 请求失败: + new String(arg2));
}
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
// TODO Auto-generated method stub
Log.i(TAG, 请求成功: + new String(arg2));
}
});
1,将下载好的源码拷贝到src目录下
2,创建一个AsyncHttpClient的对象
3,创建请求参数,RequestParams对象,请求参数仅仅包含文件对象即可,例如:
params.put(profile_picture, new File(/sdcard/pictures/pic.jpg));
4,调用该类的post方法发POST,传入请求资源地址URL,请求参数RequestParams,创建AsyncHttpResponseHandler对象
5,重写AsyncHttpResponseHandler下的两个方法,onSuccess和onFailure方法
Volley是一个由Google官方推出的网络通信库,它使得Android进行网络请求时更加方便、快速、健壮,同时对网络图片加载也提供了良好的支持。
将编译得到的jar包引入到我们的项目中;可以通过网络搜索下载,也可以在此下载
http://download.csdn.net/detail/fenghai22/8472045
使用Volley必须在AndroidManifest.xml中添加 android.permission.INTERNET权限,使用Volley时Google建议创建volley单例工具类
public class VolleySingleton {
private static VolleySingleton volleySingleton;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private Context mContext;
public VolleySingleton(Context context) {
this.mContext = context;
mRequestQueue = getRequestQueue();
mImageLoader = new ImageLoader(mRequestQueue,
new ImageLoader.ImageCache(){
private final LruCache cache = new LruCache(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 VolleySingleton getVolleySingleton(Context context){
if(volleySingleton == null){
volleySingleton = new VolleySingleton(context);
}
return volleySingleton;
}
public RequestQueue getRequestQueue(){
if(mRequestQueue == null){
mRequestQueue = Volley.newRequestQueue(mContext.getApplicationContext());
}
return mRequestQueue;
}
public void addToRequestQueue(Request req){
getRequestQueue().add(req);
}
public ImageLoader getImageLoader() {
return mImageLoader;
}
}
首先使用 Volley.newRequestQueue获取 RequestQueue对象
RequestQueue mRequestQueue = VolleySingleton.getVolleySingleton(this.getApplicationContext()).getRequestQueue();
RequestQueue是请求队列对象,它可以缓存所有的HTTP网络请求,然后按照其内部算法并发的发送这些网络请求,它能够很好的支撑高并发请求,不要每个请求都创建RequestQueue对象,创建多个RequestQueue会耗费资源
发送StringRequest请求
StringRequest stringRequest = new StringRequest(Request.Method.GET,"https://www.baidu.com",new Listener(){
@Override
public void onResponse(String s) {
//打印请求返回结果
Log.e("volley",s);
}
},new ErrorListener(){
@Override
public void onErrorResponse(VolleyError volleyError) {
Log.e("volleyerror","erro2");
}
});
//将StringRequest对象添加进RequestQueue请求队列中
VolleySingleton.getVolleySingleton(this.getApplicationContext()).addToRequestQueue(stringRequest);
到此已经完成了StringRequest请求。StringRequest提供了两个构造方法
public StringRequest(java.lang.String url, com.android.volley.Response.Listener listener, com.android.volley.Response.ErrorListener errorListener);
public StringRequest(int method, java.lang.String url, com.android.volley.Response.Listener listener, com.android.volley.Response.ErrorListener errorListener);
参数method是HTTP的请求类型,通常有GET和POST两种;参数url是请求地址;参数listener是服务器响应成功的回调,参数errorListener是服务器响应失败的回调。如果想通过POST方式请求并携带参数,遗憾的是StringRequest并没有提供带参数请求,但是当发送POST请求时,Volley会调用StringRequest的父类Request的getParams()方法来获取POST参数,所以我们只要使用StringRequest匿名类重写getParams()方法将参数传递进去就可以实现带参数的StringRequest请求。
StringRequest stringRequest = new StringRequest(Method.POST, url, listener, errorListener) {
@Override
protected Map getParams() throws AuthFailureError {
Map map = new HashMap();
map.put("params1", "value1");
map.put("params2", "value2");
return map;
}
};
发送JsonObjectRequest请求
JsonObjectRequest jr = new JsonObjectRequest(Request.Method.GET,url,null,new Response.Listener(){
@Override
public void onResponse(JSONObject jsonObject) {
Log.e("volley",jsonObject.toString());
}
},new ErrorListener(){
@Override
public void onErrorResponse(VolleyError volleyError) {
Log.e("volleyerror","erro");
}
});
VolleySingleton.getVolleySingleton(this.getApplicationContext()).addToRequestQueue(jr);
JsonObjectRequest的构造方法参数和StringRequest一致,不在此累赘。
使用ImageRequest加载图片
ImageView mImageView;
String url = "http://i.imgur.com/7spzG.png";
mImageView = (ImageView) findViewById(R.id.myImage);
ImageRequest request = new ImageRequest(url,
new Response.Listener() {
@Override
public void onResponse(Bitmap bitmap) {
mImageView.setImageBitmap(bitmap);
}
}, 0, 0, Config.RGB_565,
new Response.ErrorListener() {
public void onErrorResponse(VolleyError error) {
mImageView.setImageResource(R.drawable.image_load_error);
}
});
VolleySingleton.getVolleySingleton(this.getApplicationContext()).addToRequestQueue(request);
ImageRequest的构造函数
public ImageRequest(java.lang.String url, com.android.volley.Response.Listener listener, int maxWidth, int maxHeight, android.graphics.Bitmap.Config decodeConfig, com.android.volley.Response.ErrorListener errorListener) { /* compiled code */ }
参数url是图片地址,参数listener是请求响应成功回调,参数maxWidth是图片最大宽度,参数maxHeight是图片最大高度,如果指定的网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩,指定成0的话就表示不管图片有多大,都不会进行压缩。参数decodeConfig是图片的颜色属性,其值是Bitmap.Config类的几个常量,参数errorListener是请求响应失败回调
使用 ImageLoader 加载图片
ImageLoader mImageLoader;
ImageView mImageView;
private static final String IMAGE_URL =
"http://developer.android.com/images/training/system-ui.png";
mImageView = (ImageView) findViewById(R.id.regularImageView);
mImageLoader = VolleySingleton.getVolleySingleton(this.getApplicationContext()).getImageLoader();
//IMAGE_URL是图片网络地址
//mImageView是ImageView实例
//R.drawable.def_image默认图片id
//R.drawable.err_image加载图片错误时的图片
mImageLoader.get(IMAGE_URL, ImageLoader.getImageListener(mImageView,
R.drawable.def_image, R.drawable.err_image));
使用NetworkImageView加载图片
XML布局文件
代码
ImageLoader mImageLoader;
NetworkImageView mNetworkImageView;
private static final String IMAGE_URL =
"http://developer.android.com/images/training/system-ui.png";
mNetworkImageView = (NetworkImageView) findViewById(R.id.networkImageView);
mImageLoader = VolleySingleton.getVolleySingleton(this.getApplicationContext()).getImageLoader();
mNetworkImageView.setImageUrl(IMAGE_URL, mImageLoader);
我们可以调用它的setDefaultImageResId()方法、setErrorImageResId()方法和setImageUrl()方法来分别设置加载中显示的图片,加载失败时显示的图片
取消网络请求
Volley还提供了取消网络请求的方法并且可以联动Activity的生命周期,比如在Activity的onStop()方法中调用cance()方法取消网络请求。
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);
Activity的onStop()方法
@Override
protected void onStop () {
super.onStop();
if (mRequestQueue != null) {
mRequestQueue.cancelAll(TAG);
}
}