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;

	/**
	 * 

* Title: *

*

* Description:构造方法,其实在这里可以传入一个传输协议包,博主是测试代码,所以请求中直接写死了。 *

* * @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 
 */
public interface FreedomDataCallBack {

	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() {

			@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() {

			@Override
			public void onStart() {
				
			}

			@Override
			public void processData(String paramObject, boolean paramBoolean) {
				post.setText(paramObject);
			}

			@Override
			public void onFinish() {
				
			}

			@Override
			public void onFailed() {
				
			}
		});
	}

我们这里分别采用了两种方法访问,传入参数也是不同的,我们看访问结果,两个textView均显示了访问返回的值。
Android开发之网络请求通信专题(一):基于HttpURLConnection的请求通信_第1张图片



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


你可能感兴趣的:(Android技术)