基于HttpURLConnection的网络访问工具
来源:互联网 发布:逍遥问道登录器源码 编辑:程序博客网 时间:2024/06/11 13:24
出于完善我个人的理论了解面,再加上google在6.0之后取消了HttpClient,所以我特地抽了点时间针对HttpUrlConnection做了一点连接,并写了个工具类,方便以后可以用上,那么话不多说,直接上代码,我再代码中注释已经做得很详细了
基于对于代码结构的我个人的结构优化思维,所以并不是直接将下载的代码写好,而是搭建了一下大概的结构,大致来说分为了 模型层、数据层、控制层
首先是模型层
/** * 用来存放网络返回数据的类 * @author yjh * */public class UrlResponseBean {//idprivate String mId;//响应结果:成功、网络出错、服务器出错private int mResponseResult;//具体的响应返回码private int mResponseCode;//响应成功后返回的内容,这里返回流//private InputStream mIs;//获取网的网络数据,已经转化为输出流了private ByteArrayOutputStream mBaos;//响应成功后返回的数据private String mResponseData;private HttpURLConnection mConnectBean;public int getResponseResult() {return mResponseResult;}public void setResponseResult(int responseResult) {this.mResponseResult = responseResult;}public int getResponseCode() {return mResponseCode;}public void setResponseCode(int responseCode) {this.mResponseCode = responseCode;}public String getId() {return mId;}public void setId(String id) {this.mId = id;}public String getResponseData() {return mResponseData;}public void setResponseData(String responseData) {this.mResponseData = responseData;}protected HttpURLConnection getConnectBean() {return mConnectBean;}protected void setConnectBean(HttpURLConnection connectBean) {this.mConnectBean = connectBean;}public ByteArrayOutputStream getBaos() {return mBaos;}public void setBaos(ByteArrayOutputStream mBaos) {this.mBaos = mBaos;}}然后是数据层:
public class UrlConnectTool {private static final int TIMEOUT_IN_MILLIONS = 5000;/** * 在2.3以上,想要卡主进程运行访问网络时,需要设置这个 */@SuppressLint("NewApi")public void downloadInit(){StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads() .detectDiskWrites() .detectNetwork() .penaltyLog() .build()); StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectLeakedSqlLiteObjects() .detectLeakedClosableObjects() .penaltyLog() .penaltyDeath() .build()); }/** * 卡主线程的get下载方式 * 这里返回的bean里面是下载结果以及下载内容 */public UrlResponseBean doGet(String urlStr) {UrlResponseBean bean = new UrlResponseBean();URL url = null;HttpURLConnection conn = null;try {url = new URL(urlStr);conn = (HttpURLConnection) url.openConnection();//这里在写的时候我就一直想着在设置好超时之后,当超时时是怎么个反馈方式,网上大都是设置完了就不管了,也没有说超时//时是怎么个响应方式,我好不容易看到个说是会在抛出的错误里面返回的,但是也需要验证,但我没有可以用于测试//超时的网址!需要测试!conn.setReadTimeout(TIMEOUT_IN_MILLIONS);conn.setConnectTimeout(TIMEOUT_IN_MILLIONS);conn.setRequestMethod("GET");conn.setRequestProperty("accept", "*/*");conn.setRequestProperty("connection", "Keep-Alive");conn.setRequestProperty("Charset", "UTF-8");//设置编码格式int connectCode = conn.getResponseCode();//这里获取之后,如果需要统计,则可以在这里统计连接之后的错误信息码bean.setResponseCode(connectCode);bean.setConnectBean(conn);//在这里,对于控制层来说,只需要知道是成功,还是网络不好(让用户调整网络状态),或者是连接失败(让用户刷新)switch ((connectCode/100)) {case 2://表示成功bean.setResponseResult(UrlResponseConsts.DOWNLOAD_SUCCESS);bean.setBaos(inputToByteArrayOutputStream(conn.getInputStream()));//bean.setIs(conn.getInputStream());return bean;case 4://表示访问网址出错bean.setResponseResult(UrlResponseConsts.SERVER_ERROR);return bean;case 5://表示服务器出错bean.setResponseResult(UrlResponseConsts.SERVER_ERROR);return bean;}} catch (ProtocolException e) {//如果没有建立连接并执行getInputStream//在调用getResponseCode的时候,该函数会自动执行getInputStream并获取Response Code//所以你在此函数后再设置Request Type就会造成Connection already established错误。e.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;}//这个抛出的错我是针对连接超时时做的处理catch (SocketTimeoutException e) {//连接超时,Socket读数据的超时,https://twitter.com/我用的推特来测试出来了e.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;}//这个抛出的错我是针对连接超时时做的处理catch (ConnectTimeoutException e) {//响应超时,通过网络与服务器建立连接的超时e.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;}catch (IOException e) {//错误1:连接失败,没有网络在我用推特主页测试的时候,此时我关闭了网络,这里的报错为java.net.UnknownHostExceptione.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;}finally {try {if (conn.getInputStream() != null)conn.getInputStream().close();} catch (IOException e) {}conn.disconnect();}//此时是既不是成功也不是失败,应该属于服务器问题bean.setResponseResult(UrlResponseConsts.SERVER_ERROR);return bean;}/** * 采用post方式访问网络 */public UrlResponseBean doPost(String urlStr,String param){PrintWriter out = null; // BufferedReader in = null; UrlResponseBean bean = new UrlResponseBean(); HttpURLConnection conn = null; try { URL realUrl = new URL(urlStr); // 打开和URL之间的连接 conn = (HttpURLConnection) realUrl .openConnection(); // 设置通用的请求属性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestMethod("POST"); //设置文件类型 // application/x-www-form-urlencoded: 窗体数据被编码为名称/值对。这是标准的编码格式。 //multipart/form-data: 窗体数据被编码为一条消息,页上的每个控件对应消息中的一个部分。 //text/plain: 窗体数据以纯文本形式进行编码,其中不含任何控件或格式字符。 //form的enctype属性为编码方式,常用有两种:application/x-www-form-urlencoded和 //multipart/form-data,默认为application/x-www-form-urlencoded。 //当action为get时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1&name2=value2...), //然后把这个字串append到url后面,用?分割,加载这个新的url。 当action为post时候,浏览器把form数据封装到http body中,然后发送到server。 //如果没有type=file的控件,用默认的application/x-www-form-urlencoded就可以了。 但是如果有type=file的话,就要用到multipart/form-data了。 //浏览器会把整个表单以控件为单位分割,并为每个部分加上Content-Disposition(form-data或者file),Content-Type(默认为text/plain),name(控件name)等信息,并加上分割符(boundary)。 conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); conn.setRequestProperty("charset", "utf-8"); //设置不使用缓存 conn.setUseCaches(false); // 发送POST请求必须设置如下两行 //设置容许输出,设置了之后才能用post conn.setDoOutput(true); // 设置是否从httpUrlConnection读入,默认情况下是true; conn.setDoInput(true); conn.setReadTimeout(TIMEOUT_IN_MILLIONS); conn.setConnectTimeout(TIMEOUT_IN_MILLIONS); if (param != null && !param.trim().equals("")) { // 获取URLConnection对象对应的输出流 out = new PrintWriter(conn.getOutputStream()); // 发送请求参数 out.print(param); // flush输出流的缓冲 out.flush(); } int connectCode = conn.getResponseCode();//这里获取之后,如果需要统计,则可以在这里统计连接之后的错误信息码bean.setResponseCode(connectCode);bean.setConnectBean(conn);//在这里,对于控制层来说,只需要知道是成功,还是网络不好(让用户调整网络状态),或者是连接失败(让用户刷新)switch ((connectCode/100)) {case 2://表示成功bean.setResponseResult(UrlResponseConsts.DOWNLOAD_SUCCESS);bean.setBaos(inputToByteArrayOutputStream(conn.getInputStream()));//bean.setIs(conn.getInputStream());return bean;case 4://表示访问网址出错bean.setResponseResult(UrlResponseConsts.SERVER_ERROR);return bean;case 5://表示服务器出错bean.setResponseResult(UrlResponseConsts.SERVER_ERROR);return bean;} } catch (ProtocolException e) {//如果没有建立连接并执行getInputStream//在调用getResponseCode的时候,该函数会自动执行getInputStream并获取Response Code//所以你在此函数后再设置Request Type就会造成Connection already established错误。e.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;}//这个抛出的错我是针对连接超时时做的处理catch (SocketTimeoutException e) {//连接超时,Socket读数据的超时,https://twitter.com/我用的推特来测试出来了e.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;}//这个抛出的错我是针对连接超时时做的处理catch (ConnectTimeoutException e) {//响应超时,通过网络与服务器建立连接的超时e.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;}catch (IOException e) {//错误1:连接失败,没有网络在我用推特主页测试的时候,此时我关闭了网络,这里的报错为java.net.UnknownHostExceptione.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;} // 使用finally块来关闭输出流、输入流 finally { try { if (out != null) { out.close(); } if (conn.getInputStream() != null) conn.getInputStream().close(); } catch (IOException e) { } if(null != conn) conn.disconnect(); } //此时是既不是成功也不是失败,应该属于服务器问题 bean.setResponseResult(UrlResponseConsts.SERVER_ERROR); return bean;}private ByteArrayOutputStream inputToByteArrayOutputStream(InputStream is) throws IOException{if (null != is) {ByteArrayOutputStream baos = new ByteArrayOutputStream();int len = -1;byte[] buf = new byte[128];while ((len = is.read(buf)) != -1) {baos.write(buf, 0, len);}baos.flush();return baos;}return null;}}
下一个是控制层:
public class UrlConnectCenter {private UrlConnectTool mConnectTool;private DataKeepTool mDataTool;public UrlConnectCenter() {mConnectTool = new UrlConnectTool();mDataTool = new DataKeepTool();}/** * 卡滞主线程的网络连接,这里处理好post和get方式以及返回来的结果,过滤下载结果 这里是UrlConnectTool之后的第二层处理 */public UrlResponseBean startConnectUi(UrlConnectDescription description) {systemAdjustment();UrlResponseBean response = new UrlResponseBean();// 这里获取到访问后的结果if (!description.getIsPost()) {// get方式String connectUrl = description.getConnectUrl();// get方式时拼起来if(null != description.getConnectData())connectUrl +="?"+ description.getConnectData();response = mConnectTool.doGet(connectUrl);} else {// post方式response = mConnectTool.doPost(description.getConnectUrl(), description.getConnectData());}// 设置下载的idresponse.setId(description.getId());// 下载成功时if (response.getResponseResult() == UrlResponseConsts.DOWNLOAD_SUCCESS) {// 在这一层处理好数据,是作为数据返回还是文件存储等try {if (null == description.getFilePath()) {// 将流转化为字符String backInfo = mDataTool.getDataBackInfo(response.getBaos());response.setResponseData(backInfo);} else {// 将流转化为文件并保存mDataTool.getDataSaveFile(response.getBaos(),description.getFilePath());}} catch (IOException e) {//这里报错就是流转化时的流报错e.printStackTrace();}// 用完之后将流关闭try {response.getBaos().close();} catch (IOException e) {e.printStackTrace();}}return response;}/** * 在2.3之前可以直接在主进程之中卡主线程下载 * 但是2.3之后需要设置过后才能在主线程下载 */private void systemAdjustment(){if (android.os.Build.VERSION.SDK_INT > 9) {mConnectTool.downloadInit();}}}
控制层中也有一个bean,用于存放任务的描述
/** * 网络连接描述,用于需要发起网络连接时填充所需数据之后使用 * @author yjh * */public class UrlConnectDescription {//idprivate String mId;//需要访问的网址private String mConnectUrl;//是否是post方式private boolean mIsPost = false;//文件下载的路径,当需要下载为文件时private String mFilePath;//网址之后需要添加的参数,这里单独传入,以便于内部处理post或者getprivate String mConnectData;public String getId() {return mId;}public void setId(String mId) {this.mId = mId;}public String getConnectUrl() {return mConnectUrl;}public void setConnectUrl(String mConnectUrl) {this.mConnectUrl = mConnectUrl;}public boolean getIsPost() {return mIsPost;}public void setIsPost(boolean mIsPost) {this.mIsPost = mIsPost;}public String getFilePath() {return mFilePath;}public void setFilePath(String mFilePath) {this.mFilePath = mFilePath;}public String getConnectData() {return mConnectData;}public void setConnectData(String mConnectData) {this.mConnectData = mConnectData;}}
然后有一个工具类,用于转换流成为String 内容以及保存为文件
/** * 处理数据 * * @author yjh * */public class DataKeepTool {/** * 将访问后返回的数据转化为String类型并返回 * * @param conn * @param is * @param baos * @return * @throws IOException */public String getDataBackInfo(ByteArrayOutputStream boas) throws IOException {if (null != boas) {//采用这种方式防止出现乱码byte[] lens = boas.toByteArray();return new String(lens);}return null;}/** * 用于将流保存为文件 * * @param is */public void getDataSaveFile(ByteArrayOutputStream baos, String filePath) {FileOutputStream fos = null; try { fos = new FileOutputStream(new File(filePath)); baos.writeTo(fos); fos.close(); baos.flush(); baos.close(); } catch (IOException ioe) { ioe.printStackTrace(); } finally { }}}
代码到这边基本就够用了,还有一个的话是常亮类,这个类内容很简单,就三个访问状态的常量而已
由于在代码中注释已经写得很多了,我再这里就不再做多的描述了
这里还差的最后一个文件上传的话我再找时间补充完整
0 0
- 基于HttpURLConnection的网络访问工具
- android 中访问网络介绍 一 (基于httpurlconnection 的中get请求)
- httpurlconnection访问网络上的数据
- android 访问网络二 (基于httpurlconnection post)
- HttpURLConnection:网络下载数据的工具类
- HttpURLConnection(访问网络)
- 使用HttpURLConnection访问网络
- HttpURLConnection访问网络
- 使用HttpURLConnection访问网络
- android HttpURLConnection网络访问
- 使用HttpURLConnection访问网络
- 用HttpURLConnection访问网络
- 网络访问之HttpURLConnection
- 使用HttpURLConnection访问网络
- 网络访问之HttpURLConnection
- 【封装】异步HttpURLConnection网络访问
- 网络访问——HttpURLConnection
- Android 之 HttpURLConnection 访问网络
- Twitter 帐号申请解封
- Android客户端解析服务器端WebService返回来的JSON数据(有源码,调试成功)
- Hadoop 案例7-----日志分析:分析非结构化文件
- 尽量避免官司缠身
- 排序算法之Java实现2——堆排序算法
- 基于HttpURLConnection的网络访问工具
- 笔试基础(第二篇
- 栈(stack)
- Autumn is coming
- NSAutoreleasePool实现原理
- 排序算法之Java实现3——直接插入排序算法
- PDF开源库libharu的折腾之旅
- 算法----优先队列
- 排序之-----快速排序