封装android http框架
来源:互联网 发布:新闻联播图片素材软件 编辑:程序博客网 时间:2024/06/05 06:01
目前有几个开源的android http框架,比如volley、android-async-http,对于初学者来说听上去可能很高大上,实际就是对常用的网络请求代码做了一下封装,看过一套框架源码以后就会感觉没那么复杂,我们完全可以自己封装一个http框架。
需求分析:
1. 支持http协议:GET、POST、PUT、DELETE
2. 支持apache的HttpClient和原生的HttpURLConnection两种请求方式
3. 异步请求(使用AsyncTask或Thread+Handler)
4. 支持多线程上传下载(使用RandomAccessFile)
5. 请求错误统一处理(可自定义Exception)
6. 预处理服务端返回的数据
7. 上传下载进度更新
8. 支持断点续传
9. 随时取消网络请求
10. 关联activity(activity被回收时,请求应终止)
类图:
时序图:
关键代码:
public class RequestTask extends AsyncTask<Object, Integer, Object>{ private Request mRequest; public RequestTask(Request request){ mRequest = request; } @Override protected Object doInBackground(Object... params) { try { /* HttpClient请求方式 HttpResponse httpResponse = HttpClientUtils.request(mRequest); return mRequest.mCallback.handleResponse(httpResponse, new ProgressCallback() { @Override public void onProgressUpdate(int curPos, int contentLength) { publishProgress(curPos, contentLength); } }); */ // HttpURLConnection请求方式 InputStream is = HttpUrlConnUtils.request(mRequest); return mRequest.mCallback.handleResponse(is, new ProgressCallback() { @Override public void onProgressUpdate(int curPos, int contentLength) { publishProgress(curPos, contentLength); } }); } catch (Exception e) { return e; } } @Override protected void onPostExecute(Object o) { if(o instanceof Exception){ mRequest.mCallback.onFail((Exception) o); }else{ mRequest.mCallback.onSuccess(o); } } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); if(mRequest.mProgressCallback != null){ mRequest.mProgressCallback.onProgressUpdate(values[0], values[1]); } }}
public class HttpClientUtils { public static HttpResponse request(Request request) throws Exception { switch (request.mRequestMethod){ case GET: return get(request); case POST: return post(request); default: throw new IllegalStateException("The request's request method is illegal"); } } public static HttpResponse get(Request request) throws Exception{ HttpClient httpClient = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(request.mUrl); addHeader(httpGet, request.mHeaderMap); return httpClient.execute(httpGet); } public static HttpResponse post(Request request) throws Exception{ HttpClient httpClient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost(request.mUrl); httpPost.setEntity(new StringEntity(request.mPostContent)); addHeader(httpPost, request.mHeaderMap); return httpClient.execute(httpPost); } public static void addHeader(HttpUriRequest httpUriRequest, Map<String, String> headers){ if(headers == null){ return; } for (Map.Entry<String, String> entry : headers.entrySet()) { httpUriRequest.addHeader(entry.getKey(), entry.getValue()); } }}
public class HttpUrlConnUtils { public static InputStream request(Request request){ switch (request.mRequestMethod){ case GET: return get(request); case POST: return post(request); } return null; } private static InputStream get(Request request) { try { URL url = new URL(request.mUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); addHeader(conn, request.mHeaderMap); return conn.getInputStream(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } private static InputStream post(Request request) { try { URL url = new URL(request.mUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setConnectTimeout(5000); addHeader(conn, request.mHeaderMap); conn.setDoInput(true); if(!TextUtils.isEmpty(request.mPostContent)){ conn.setDoOutput(true); OutputStreamWriter osw = new OutputStreamWriter(conn.getOutputStream(), "utf-8"); BufferedWriter bw = new BufferedWriter(osw); bw.write(request.mPostContent); bw.flush(); } return conn.getInputStream(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } private static void addHeader(HttpURLConnection conn, Map<String, String> headerMap) { if(headerMap == null){ return; } conn.addRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)"); for(Map.Entry<String, String> entry : headerMap.entrySet()){ conn.addRequestProperty(entry.getKey(), entry.getValue()); } }}
public abstract class AbstractCallback implements ICallback{ public String path; //处理HttpURLConnection请求方式的返回流 @Override public Object handleResponse(InputStream inputStream, ProgressCallback callback) { try { if(!TextUtils.isEmpty(path)){ FileOutputStream fos = new FileOutputStream(path); byte[] b = new byte[1024]; int len; while((len = inputStream.read(b)) != -1){ fos.write(b, 0, len); } fos.flush(); inputStream.close(); fos.close(); return IOUtils.readFromFile(path); }else{ return IOUtils.inputStream2Str(inputStream); } } catch (FileNotFoundException e) { e.printStackTrace(); return e; } catch (IOException e) { e.printStackTrace(); return e; } } //处理HttpClient请求方式的返回实体 public Object handleResponse(HttpResponse httpResponse, ProgressCallback progressCallback){ try { HttpEntity httpEntity = httpResponse.getEntity(); int statusCode = httpResponse.getStatusLine().getStatusCode(); switch (statusCode){ case HttpStatus.SC_OK: if(!TextUtils.isEmpty(path)){ FileOutputStream fos = new FileOutputStream(path); InputStream is = httpEntity.getContent(); byte[] b = new byte[1024]; int len; int curPos = 0; int contentLength = (int) httpEntity.getContentLength(); while((len = is.read(b)) != -1){ curPos += len; fos.write(b, 0, len); if(progressCallback != null){ progressCallback.onProgressUpdate(curPos, contentLength); } } fos.flush(); is.close(); fos.close(); return bindData(path); }else{ return bindData(EntityUtils.toString(httpEntity)); } } } catch (IOException e) { e.printStackTrace(); return e; } return null; } //子类需复写该方法 protected Object bindData(String content) { return content; } public AbstractCallback setPath(String path){ this.path = path; return this; }}
public abstract class StringCallback extends AbstractCallback{ @Override protected Object bindData(String content) { if(!TextUtils.isEmpty(path)){ return IOUtils.readFromFile(path); }else{ return content; } }}
public class IOUtils { public static String readFromFile(String path){ ByteArrayOutputStream outputStream = null; FileInputStream fis = null; try { outputStream = new ByteArrayOutputStream(4 * 1024); File file = new File(path); fis = new FileInputStream(file); byte[] b = new byte[1024]; int len; while((len = fis.read(b)) != -1){ outputStream.write(b, 0, len); } outputStream.flush(); return new String(outputStream.toByteArray()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(outputStream != null){ try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if(fis != null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } public static String inputStream2Str(InputStream is){ try { String str; StringBuffer sb = new StringBuffer(); BufferedReader br = new BufferedReader(new InputStreamReader(is, "utf-8")); while((str = br.readLine()) != null){ sb.append(str); } return sb.toString(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return ""; }}
说明:
1.如需要实时显示当前上传下载进度的百分比,就需要有服务端返回实体的总长度。但拿到HttpResponse的HttpEntity时,调用getContentLength()结果却是-1。解决方案:
request之前添加header,伪装成浏览器:
httpGet.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)");
2.关于多线程分段下载和断点续传的实现,后续博客会有更新。
0 0
- 封装android http框架
- android http交互框架二次封装
- 使用android-async-http来封装Android网络请求框架
- 自己封装的android客户端http网络框架
- async-http-android框架的介绍和二次封装
- Android基于http封装的网络请求框架
- 手动封装http网络框架
- Android封装Http请求
- android-async-http 封装
- Android OkHttp封装 框架
- android http——网络请求二次封装的框架设计
- android项目后期优化-----代码重新封装/形成框架意识(http请求)
- android http——网络请求二次封装的框架设计
- Android Http网络请求封装
- Android中封装Http请求
- android Http异步请求封装
- Android http访问简单封装
- Android异步线程框架封装
- Pycharm如何设置自定义背景颜色
- angular 中 一些名词解释
- 在eclipse中使用stanford构建中文依存关系树
- 主席树 poj 2104 K-th Number
- windows下c++抓包实例
- 封装android http框架
- Java设计模式(九)单例模式
- Maven 的生命周期介绍
- 关于Windows中生成FFTW的lib文件时报LNK1104错误
- cocos creator Button控件用法
- python操作数据库mysql
- ubuntu14.04 安装cuda8.0
- swift -基础1
- C/C++混合编程--extern “C” 使用方法详解