当前位置: 代码迷 >> Android >> Android开发之网络请求通讯专题(一):基于HttpURLConnection的请求通信
  详细解决方案

Android开发之网络请求通讯专题(一):基于HttpURLConnection的请求通信

热度:54   发布时间:2016-04-28 02:37:49.0
Android开发之网络请求通信专题(一):基于HttpURLConnection的请求通信

在Android开发中,网络请求必然是必不可少。一般而言,都是基于http的网络请求。有时候也会有SOCKET请求,这个后续的专题再讲。今天,我们就先讲讲常用的Http请求。

http请求自然是遵循http协议的,相关内容请转接:Java学习笔记之Http协议详解

好了,开始今天的正题。


一、基础HTTPURL请求方式

我们先来看一个最简单的例子,通过get方法请求拿到返回值

1、用get方式请求

URL url = new URL(					"http://192.168.31.144:10010/MINATest/servlet/DataTestServlet?username=victor&password=strikefreedom");			HttpURLConnection conn = (HttpURLConnection) url.openConnection();			conn.setRequestMethod("GET");			conn.setConnectTimeout(TIME);			conn.setReadTimeout(TIME);			int responseCode = conn.getResponseCode();			if (responseCode == 200) {				input = conn.getInputStream();				if (input != null) {					//拿到流后处理									}							}

2、用post方式请求

String data = "username=justice&password=infiniteJustice";			URL url = new URL(					"http://192.168.31.144:10010/MINATest/servlet/DataTestServlet");			conn = (HttpURLConnection) url.openConnection();			conn.setConnectTimeout(TIME);			conn.setReadTimeout(TIME);			conn.setDoInput(true);// 允许输入			conn.setDoOutput(true);// 允许输出			conn.setUseCaches(false);// 不使用Cache			conn.setRequestProperty("Charset", ENCODING);			conn.setRequestProperty("Content-Length",					String.valueOf(data.length()));			conn.setRequestProperty("Content-Type", "text/*;charset=utf-8");			conn.setRequestMethod("POST");			DataOutputStream outStream = new DataOutputStream(					conn.getOutputStream());			outStream.write(data.getBytes());			outStream.flush();			outStream.close();			if (conn == null) {				return;			}			int responseCode = conn.getResponseCode();			if (responseCode == 200) {				input = conn.getInputStream();				if (input != null) {									}			}

我们可以看到用post方式请求和用get方式传入参数有点不同。

二、http访问类的封装


1、封装逻辑

我们知道,在android开发中,网络访问的东西都是不能在UI线程中执行的,只能在子线程里面执行,得到结果后通知主线程刷新UI。这个消息通知机制博主就不在详细描述,有兴趣的朋友请转接:Android异步处理系列文章索引
在正常的开发中,我们不会每次请求,都像上面那样的简单去写,我们需要做一定的封装处理,来使代码更加的简洁,架构更加的清晰。那么我们需要这么四个东西

1、http访问管理者
2、消息通信管理者handler
3、http访问结果监听器
4、http访问结果事件处理回调接口。
整个逻辑关系为:http访问管理者采用get或者post请求方式请求,当产生结果后监听器告诉消息通信管理者应该发送什么消息给UI线程,UI线程更具消息通信管理者发送过来的消息,调用对应的事件处理回调接口。

那么我们来一一对应看这四个类该如何编写。

2、http访问管理者

http访问管理者,如其名,里面需要封装两种请求。正常情况下,在构造出http访问管理者的时候,需要传入一个通信协议的类进入,里面应该包含请求地址以及请求信息,这里博主为了方便省事,没有出入,直接写死了。有兴趣的同学可以根据自身实际需求更改。看代码:

package com.example.nettest;import java.io.ByteArrayOutputStream;import java.io.DataOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.UnsupportedEncodingException;import java.net.HttpURLConnection;import java.net.SocketException;import java.net.SocketTimeoutException;import java.net.URL;import java.net.URLEncoder;import java.util.HashMap;import java.util.Map;import android.content.Context;import android.text.TextUtils;import android.util.Log;/** * @ClassName: FreedomHttpUrlUtils * @author victor_freedom ([email protected]) * @createddate 2015-1-22 下午1:43:58 * @Description: http请求管理者 */public class FreedomHttpUrlUtils implements Runnable {	private Context context;	/** http访问结果监听器 */	private FreedomHttpListener listener;	/** 当前访问线程 */	private Thread currentRequest = null;	/** 访问链接 */	HttpURLConnection conn = null;	/** 拿到的流 */	InputStream input = null;	private static final String ENCODING = "UTF-8";	public static final int GET_MOTHOD = 1;	private static final int TIME = 40 * 1000;	public static final int POST_MOTHOD = 2;	/**	 * 1: get请求 2: post请求	 */	private int requestStatus = 1;	/**	 * <p>	 * Title:	 * </p>	 * <p>	 * Description:构造方法,其实在这里可以传入一个传输协议包,博主是测试代码,所以请求中直接写死了。	 * </p>	 * 	 * @param mContext	 * @param listener	 *            监听器	 * @param mRequeststatus	 *            请求方式	 */	public FreedomHttpUrlUtils(Context mContext, FreedomHttpListener listener,			int mRequeststatus) {		this.context = mContext;		this.requestStatus = mRequeststatus;		this.listener = listener;	}	/**	 * @Title: postRequest	 * @Description:Post请求触发	 * @throws	 */	public void postRequest() {		requestStatus = 2;		currentRequest = new Thread(this);		currentRequest.start();	}	/**	 * @Title: getRequeest	 * @Description:GET请求触发	 * @throws	 */	public void getRequeest() {		requestStatus = 1;		currentRequest = new Thread(this);		currentRequest.start();	}	/**	 * 对请求的字符串进行编码	 * 	 * @return	 * @throws UnsupportedEncodingException	 */	public static String requestEncodeStr(String requestStr)			throws UnsupportedEncodingException {		return URLEncoder.encode(requestStr, ENCODING);	}	/**	 * @Title: sendGetRequest	 * @Description: 发送get请求	 * @throws	 */	private void sendGetRequest() {		try {			URL url = new URL(					"http://192.168.31.144:10010/MINATest/servlet/DataTestServlet?username=victor&password=strikefreedom");			HttpURLConnection conn = (HttpURLConnection) url.openConnection();			conn.setRequestMethod("GET");			conn.setConnectTimeout(TIME);			conn.setReadTimeout(TIME);			int responseCode = conn.getResponseCode();			if (responseCode == 200) {				input = conn.getInputStream();				if (input != null) {					listener.action(FreedomHttpListener.EVENT_GET_DATA_SUCCESS,							readStream(input));				}			} else {				listener.action(FreedomHttpListener.EVENT_NETWORD_EEEOR, null);			}		} catch (SocketException e) {			e.printStackTrace();			listener.action(FreedomHttpListener.EVENT_CLOSE_SOCKET, null);		} catch (SocketTimeoutException e) {			e.printStackTrace();			listener.action(FreedomHttpListener.EVENT_NETWORD_EEEOR, null);		} catch (IOException e) {			e.printStackTrace();			listener.action(FreedomHttpListener.EVENT_GET_DATA_EEEOR, null);		} catch (Exception e) {			e.printStackTrace();			listener.action(FreedomHttpListener.EVENT_NETWORD_EEEOR, null);		}	}	/**	 * @Title: sendPostRequest	 * @Description: 发送post请求	 * @throws	 */	private void sendPostRequest() {		try {			String data = "username=justice&password=infiniteJustice";			URL url = new URL(					"http://192.168.31.144:10010/MINATest/servlet/DataTestServlet");			conn = (HttpURLConnection) url.openConnection();			conn.setConnectTimeout(TIME);			conn.setReadTimeout(TIME);			conn.setDoInput(true);// 允许输入			conn.setDoOutput(true);// 允许输出			conn.setUseCaches(false);// 不使用Cache			conn.setRequestProperty("Charset", ENCODING);			conn.setRequestProperty("Content-Length",					String.valueOf(data.length()));			conn.setRequestProperty("Content-Type", "text/*;charset=utf-8");			conn.setRequestMethod("POST");			DataOutputStream outStream = new DataOutputStream(					conn.getOutputStream());			outStream.write(data.getBytes());			outStream.flush();			outStream.close();			if (conn == null) {				return;			}			int responseCode = conn.getResponseCode();			if (responseCode == 200) {				input = conn.getInputStream();				if (input != null) {					listener.action(FreedomHttpListener.EVENT_GET_DATA_SUCCESS,							readStream(input));				}			} else if (responseCode == 404) {				input = conn.getErrorStream();				if (input != null) {					listener.action(FreedomHttpListener.EVENT_GET_DATA_SUCCESS,							readStream(input));				} else {					listener.action(FreedomHttpListener.EVENT_NETWORD_EEEOR,							null);				}			} else {				listener.action(FreedomHttpListener.EVENT_NETWORD_EEEOR, null);			}		} catch (SocketException e) {			e.printStackTrace();			listener.action(FreedomHttpListener.EVENT_CLOSE_SOCKET, null);		} catch (SocketTimeoutException e) {			e.printStackTrace();			listener.action(FreedomHttpListener.EVENT_NETWORD_EEEOR, null);		} catch (IOException e) {			e.printStackTrace();			listener.action(FreedomHttpListener.EVENT_GET_DATA_EEEOR, null);		} catch (Exception e) {			e.printStackTrace();			listener.action(FreedomHttpListener.EVENT_NETWORD_EEEOR, null);		}	}	/**	 * @Title: isRunning	 * @Description: 判断是否正在访问	 * @return	 * @throws	 */	public boolean isRunning() {		if (currentRequest != null && currentRequest.isAlive()) {			return true;		}		return false;	}	/**	 * 读取数据	 * 	 * @param inStream	 *            输入流	 * @return	 * @throws Exception	 */	private Object readStream(InputStream inStream) throws Exception {		String result;		ByteArrayOutputStream outStream = new ByteArrayOutputStream();		byte[] buffer = new byte[1024];		int len = -1;		while ((len = inStream.read(buffer)) != -1) {			outStream.write(buffer, 0, len);		}		result = new String(outStream.toByteArray(), ENCODING);		outStream.close();		inStream.close();		return result;	}	/**	 * 取消当前HTTP连接处理	 */	public void cancelHttpRequest() {		if (currentRequest != null && currentRequest.isAlive()) {			if (input != null) {				try {					input.close();				} catch (Exception e) {					e.printStackTrace();				}			}			input = null;			if (conn != null) {				try {					conn.disconnect();				} catch (Exception e) {					e.printStackTrace();				}			}			conn = null;			currentRequest = null;			System.gc();		}	}	/**	 * 发送请求	 */	public void run() {		// 判断是否有网络		boolean netType = NetUtils.checkNetWork(context);		if (netType) {			if (requestStatus == 1) {				sendGetRequest();			} else if (requestStatus == 2) {				sendPostRequest();			}		} else {			listener.action(FreedomHttpListener.EVENT_NOT_NETWORD, null);		}	}}

我们可以看到,当访问有结果以后,会出发监听器的action方法,那么我们再来看看监听器的定义

3、http访问结果监听器

package com.example.nettest;/** * @ClassName: FreedomHttpListener * @author victor_freedom ([email protected]) * @createddate 2015-1-24 下午4:28:31 * @Description: 监听器 */public interface FreedomHttpListener {	public static final int EVENT_BASE = 0x100;	/**	 * 没有网络的信息提示	 * */	public static final int EVENT_NOT_NETWORD = EVENT_BASE + 1;	/**	 * 网络异常的信息提示	 * */	public static final int EVENT_NETWORD_EEEOR = EVENT_BASE + 2;	/**	 * 获取网络数据失败	 * */	public static final int EVENT_GET_DATA_EEEOR = EVENT_BASE + 3;	/**	 * 获取网络数据成功	 * */	public static final int EVENT_GET_DATA_SUCCESS = EVENT_BASE + 4;	/**	 * 获取网络数据成功	 * */	public static final int EVENT_CLOSE_SOCKET = EVENT_BASE + 5;	public void action(int actionCode, Object object);}

我们可以看到,在触发action动作的时候,我们会传入一个code和一个对象,这个code表示当前访问是否成功,而对象就是要传输的访问结果。
我们再看看消息处理器是如何工作的

4、消息处理器

/**	 * @ClassName: BaseHandler	 * @author victor_freedom ([email protected])	 * @createddate 2015-1-24 下午4:32:05	 * @Description: 消息处理器	 */	class BaseHandler extends Handler {		private Context context;		/** 事件回调接口处理 */		private FreedomDataCallBack callBack;		public BaseHandler(Context context, FreedomDataCallBack callBack) {			this.context = context;			this.callBack = callBack;		}		public void handleMessage(Message msg) {			// 根据不同的结果触发不同的动作			if (msg.what == FreedomHttpListener.EVENT_GET_DATA_SUCCESS) {				if (msg.obj == null) {					callBack.onFailed();				} else {					// 后台处理数据					callBack.processData(msg.obj, true);				}			} else if (msg.what == FreedomHttpListener.EVENT_NOT_NETWORD) {				callBack.onFailed();				// CommonUtil.showInfoDialog(context,				// getString(R.string.net_error));			} else if (msg.what == FreedomHttpListener.EVENT_NETWORD_EEEOR) {				callBack.onFailed();			} else if (msg.what == FreedomHttpListener.EVENT_GET_DATA_EEEOR) {				callBack.onFailed();			} else if (msg.what == FreedomHttpListener.EVENT_CLOSE_SOCKET) {			}			callBack.onFinish();		}	}

我们可以看到,在消息处理器中传入了一个回调接口类,在不同的返回结果中,触发不同的回调动作。

5、回调接口

package com.example.nettest;/** * @ClassName: FreedomDataCallBack * @author victor_freedom ([email protected]) * @createddate 2015-1-24 下午4:33:38 * @Description: 回调接口,处理返回数据 * @param <T> */public interface FreedomDataCallBack<T> {	public abstract void onStart();	public abstract void processData(T paramObject, boolean paramBoolean);	public abstract void onFinish();	public abstract void onFailed();}

因为我们不知道返回的结果是什么类型的,这里采用泛型来处理


三、http封装后的使用

1、从服务器拿数据的方法

所有的东西我们都已经封装好了之后,该怎么使用呢?我们来尝试写一个方法吧,从服务器获取数据并返回。我们先写一个getDataFromserver的方法在基类中
	/**	 * @Title: getDataFromServer	 * @Description: 从服务器拿数据	 * @param requestType	 *            请求方式	 * @param callBack	 *            回调接口	 * @throws	 */	protected void getDataFromServer(int requestType,			FreedomDataCallBack callBack) {		final BaseHandler handler = new BaseHandler(this, callBack);		freedomHttpUrlUtils = new FreedomHttpUrlUtils(mContext,				new FreedomHttpListener() {					@Override					public void action(int actionCode, Object object) {						Message msg = new Message();						switch (actionCode) {						case FreedomHttpListener.EVENT_NOT_NETWORD:							msg.what = FreedomHttpListener.EVENT_NOT_NETWORD;							break;						case FreedomHttpListener.EVENT_NETWORD_EEEOR:							msg.what = FreedomHttpListener.EVENT_NETWORD_EEEOR;							break;						case FreedomHttpListener.EVENT_CLOSE_SOCKET:							msg.what = FreedomHttpListener.EVENT_CLOSE_SOCKET;							break;						case FreedomHttpListener.EVENT_GET_DATA_EEEOR:							msg.what = FreedomHttpListener.EVENT_GET_DATA_EEEOR;							msg.obj = null;							break;						case FreedomHttpListener.EVENT_GET_DATA_SUCCESS:							msg.obj = object;							msg.what = FreedomHttpListener.EVENT_GET_DATA_SUCCESS;							break;						default:							break;						}						handler.sendMessage(msg);					}				}, requestType);		callBack.onStart();		// 选择不同的请求方法		if (requestType == FreedomHttpUrlUtils.GET_MOTHOD) {			freedomHttpUrlUtils.getRequeest();		} else if (requestType == FreedomHttpUrlUtils.POST_MOTHOD) {			freedomHttpUrlUtils.postRequest();		}	}

2、方法的使用

我们在主Activity中启用一下这个方法。为了方便,博主这里是提交了什么参数就返回什么参数。这里提交的参数统一为username和password形式。请求详细参数请看FreedomHttpUrlUtils中。
我们先看服务端的处理方式:
	@Override	public void doGet(HttpServletRequest request, HttpServletResponse response)			throws ServletException, IOException {		String parameter = request.getParameter("username");		String parameter2 = request.getParameter("password");		System.out.println(parameter + parameter2);		response.setContentType("text/*;charset=utf-8");		response.getWriter().write(parameter + "-" + parameter2);	}	@Override	public void doPost(HttpServletRequest request, HttpServletResponse response)			throws ServletException, IOException {		// doGet(request, response);		System.out.println("post");		ServletInputStream inputStream = request.getInputStream();		ByteOutputStream b = new ByteOutputStream();		int len = -1;		byte[] buf = new byte[1024];		while ((len = inputStream.read(buf)) != -1) {			b.write(buf, 0, buf.length);		}		String s = b.toString();		String[] split = s.split("&");		System.out.println(split[0] + split[1]);		response.setContentType("text/*;charset=utf-8");		response.getWriter().write(				split[0].substring(split[0].lastIndexOf("=") + 1) + "-"						+ split[1].substring(split[1].lastIndexOf("=") + 1));	}

我们在看在activity中的调用:
/*** @ClassName: MainActivity* @author victor_freedom ([email protected])* @createddate 2015-1-24 下午4:40:59* @Description: TODO */public class MainActivity extends BaseActivity {	private TextView get;	private TextView post;	@Override	protected void findViewById() {		get = (TextView) findViewById(R.id.hello);		post = (TextView) findViewById(R.id.post);	}	@Override	protected void loadViewLayout() {		setContentView(R.layout.activity_main);	}	@Override	protected void processLogic() {	}	@Override	protected void setListener() {	}	@Override	protected void init() {		getDataFromServer(1, new FreedomDataCallBack<String>() {			@Override			public void onStart() {			}			@Override			public void processData(String paramObject, boolean paramBoolean) {				get.setText(paramObject);			}			@Override			public void onFinish() {			}			@Override			public void onFailed() {			}		});				getDataFromServer(2, new FreedomDataCallBack<String>() {			@Override			public void onStart() {							}			@Override			public void processData(String paramObject, boolean paramBoolean) {				post.setText(paramObject);			}			@Override			public void onFinish() {							}			@Override			public void onFailed() {							}		});	}

我们这里分别采用了两种方法访问,传入参数也是不同的,我们看访问结果,两个textView均显示了访问返回的值。




好了,第一篇关于http访问的文章已经讲解完毕,希望能够帮助到看到此文的人。下一篇我们讲解如何使用httpclient类来实现http网络请求,并实现文件的上传和下载功能。


  相关解决方案