从零撸一个优雅的Android Http网络框架(一)框架搭建
2017-03-27 15:10
483 查看
从零撸一个优雅的Android Http网络框架系列(一)框架搭建
此系列文章基于Java原生URLConnection打造一款优雅的HTTP网络框架,惊喜多多,学点多多,全面理解Http,做SDK时选择网络框架就有了更多选择
Github地址:https://github.com/huanghaibin-dev/HttpNet最终的完成效果是这样的:(是不是有点OkHttp的feed?)
Request request = new Request.Builder() .encode("UTF-8") .method("POST") .content(new JsonContent("json字符串") .timeout(13000) .url("http://xxx.xxxxx.com") .build(); HttpNetClient client = new HttpNetClient(); client.setProxy("192.168.1.1",80);//您也可以开启该客户端全局代理 client.newCall(request) //如果采用上传文件方式,可以在这里开启上传进度监控 .intercept(new InterceptListener() { @Override public void onProgress(final int index, final long currentLength, final long totalLength) { Log.e("当前进度", " -- " + ((float) currentLength / totalLength) * 100); } }) .execute(new Callback() { @Override public void onResponse(Response response) { String body = response.getBody();//读取字符串 InputStream is = response.toStream();//如果采用下载,可以在这里监听下载进度 } @Override public void onFailure(Exception e) { Log.e("onFailure", " onFailure " + e.getMessage()); } });
码代码之前,我们有必要先来确定一下整体框架,一个好的框架便于我们阅读、理解、迭代,总体如下图:
1、整体入口就是HttpNetClient,即创建HttpNetClient
2、创建我们的请求对象Request,这里采用静态工厂模式Builder,简单粗暴易懂,Builder由url、method、HttpContent、RequestParams、Header,Proxy等组成
3、由分发器Dispatcher并发执行我们构建的Request,所以分发器是我们创建的线程池
4、HttpContent是我们创建的请求体,所需要的请求内容由RequestParams构建而来,这里有三种:MultiPartContent、JsonContent、FormContent,分别对应POST请求的三种Content-Type:multipart/form-data || application/json; charset=utf-8 || application/x-www-form-urlencoded
5、准备就绪开始连接服务器:Connection,这里就两种:HttpConnection、HttpsConnection https需要考虑自签名证书、双向SSL验证等安全问题,当然这些都没什么压力
6、Response得到服务器的回掉,这里大有文章,我们要考虑InputStream关闭的问题、下载大文件的问题、处理各种balabala一大堆,好比AsyncHttpClient如果想下载大文件是比较麻烦的,这里我们采用类似OkHttp的方案: Response.close();
7、Callback是我们的异步回掉,当然我们可以选择同步方法,方便结合RxJava使用。
开始我们的代码之旅
构建我们的请求Requestpublic final class Request { private String mUrl;//url private String mMethod;//请求方法 private RequestParams mParams;//请求参数 private Headers mHeaders;//头部 private String mEncode;//编码 private int mTimeout;//超时 private HttpContent mHttpContent;//http请求体 private String mHost;//代理host private int mPort;//代理端口 private Request(Builder builder) { this.mUrl = builder.mUrl; this.mHeaders = builder.mHeaders.build(); this.mMethod = builder.mMethod; this.mParams = builder.mParams; this.mHttpContent = builder.mHttpContent; this.mEncode = builder.mEncode; this.mTimeout = builder.mTimeout; this.mHost = builder.mHost; this.mPort = builder.mPort; } public String url() { return mUrl; } public String method() { return mMethod; } public RequestParams params() { return mParams; } public Headers headers() { return mHeaders; } public HttpContent content() { return this.mHttpContent; } public String encode() { return mEncode; } public int timeout() { return mTimeout; } public String host() { return mHost; } public int port() { return mPort; } public static final class Builder { private String mUrl; private String mMethod; private String mEncode; private int mTimeout; private RequestParams mParams; private Headers.Builder mHeaders; private HttpContent mHttpContent; private String mHost; private int mPort; public Builder() { this.mMethod = "GET"; this.mEncode = "UTF-8"; this.mTimeout = 13000; this.mHeaders = new Headers.Builder(); } public Builder url(String url) { if (url == null) throw new NullPointerException("url can not be null"); this.mUrl = url; return this; } public Builder encode(String encode) { if (encode == null) throw new NullPointerException("encode can not be null"); this.mEncode = encode; return this; } public Builder timeout(int timeout) { this.mTimeout = timeout; if (mTimeout <= 0) mTimeout = 13000; return this; } public Builder method(String method) { if (method == null) throw new NullPointerException("method can not be null"); this.mMethod = method; return this; } public Builder params(RequestParams params) { if (params == null) throw new NullPointerException("params can not be null"); this.mParams = params; return this; } public Builder headers(Headers.Builder headers) { this.mHeaders = headers; return this; } public Builder content(HttpContent content) { if (content == null) throw new NullPointerException("content can not be null"); this.mHttpContent = content; return this; } public Builder proxy(String host, int port) { if (host == null) throw new NullPointerException("host can not be null"); this.mHost = host; this.mPort = port; return this; } public Request build() { if (mHttpContent == null && mParams != null) { if (mParams.getMultiParams() != null) { mHttpContent = new MultiPartContent(mParams, mEncode); } else { mHttpContent = new FormContent(mParams, mEncode); } } return new Request(this); } } }
看完请求Request简单粗暴有没有?接下来构建我们需要的请求参数,这里需要注意很特殊的需要:form表单有多个相同的key,所以我们采用IdentityHashMap这个特殊的HashMap,他的Key是一个对象地址,我们采用静态内部类Key包装String达到我们的需求
public final class RequestParams { private IdentityHashMap<Key, String> textParams;//表单 private IdentityHashMap<Key, File> multiParams;//文件 public RequestParams() { textParams = new IdentityHashMap<>(); } public RequestParams put(String name, String value) { textParams.put(new Key(name), value); return this; } public RequestParams put(String name, int value) { return put(name, String.valueOf(value)); } public RequestParams put(String name, long value) { return put(name, String.valueOf(value)); } public RequestParams put(String name, double value) { return put(name, String.valueOf(value)); } public RequestParams put(String name, float value) { return put(name, String.valueOf(value)); } public RequestParams put(String name, byte value) { return put(name, String.valueOf(value)); } public RequestParams put(String name, boolean value) { return put(name, String.valueOf(value)); } public RequestParams putFile(String name, File file) { if (multiParams == null) multiParams = new IdentityHashMap<>(); if (!file.exists()) return this; multiParams.put(new Key(name), file); return this; } public RequestParams putFile(String name, String fileName) { return putFile(name, new File(fileName)); } public IdentityHashMap<Key, String> getTextParams() { return textParams; } public IdentityHashMap<Key, File> getMultiParams() { return multiParams; } /** * 静态内部类包装Key */ public static class Key { private String name; public Key(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } }
接下来我们继续封装Headers,这里也需要注意Headers是可以有多个相同的key的,我们采用HttpUrlConnection.getHeaderFields();相同的Map
public class Headers { private Map<String, List<String>> mHeaders; private Headers(Builder builder) { this.mHeaders = builder.mHeaders; } public Map<String, List<String>> getHeaders() { return mHeaders; } public void setHeaders(Map<String, List<String>> mHeaders) { this.mHeaders = mHeaders; } public static final class Builder { private Map<String, List<String>> mHeaders; public Builder() { mHeaders = new HashMap<>(); } public Builder addHeader(String name, String value) { checkNotNull(name, value); if (mHeaders.containsKey(name)) { if (mHeaders.get(name) == null) mHeaders.put(value, new ArrayList<String>()); mHeaders.get(name).add(value); } else { List<String> h = new ArrayList<>(); h.add(value); mHeaders.put(name, h); } return this; } public Builder setHeader(String name, String value) { if (mHeaders.containsKey(name)) { mHeaders.remove(name); } List<String> h = new ArrayList<>(); h.add(value); mHeaders.put(name, h); return this; } private void checkNotNull(String name, String value) { if (name == null) throw new NullPointerException("name can not be null"); if (value == null) throw new NullPointerException("value can not be null"); } public Headers build() { return new Headers(this); } } }
基础框架搭建就到此结束,下一篇全面讲解HttpContent,全面理解HTTP是怎么发送的数据和报文格式
相关文章推荐
- Java&Android开源库代码剖析】のandroid-async-http(如何设计一个优雅的Android网络请求框架,同...
- Android 网络请求框架android-async-http的一个细节问题(org.apache.http.client.CircularRedirectException异常)
- android 设计一个简易的Http网络请求框架
- android框架搭建——封装一个属于自己的网络工具类
- Android_访问网络三(android-async-http框架的简单使用)
- 用.Net打造一个移动客户端(Android/IOS)的服务端框架NHM(四)——Android端Http访问类
- android 上的一个网络接口和图片框架
- Android学习之——自己搭建Http框架(1)
- Android网络框架之Http请求的分发与执行(三)
- android volley HTTP网络框架 分析
- 无废话Android之内容观察者ContentObserver、获取和保存系统的联系人信息、网络图片查看器、网络html查看器、使用异步框架Android-Async-Http(4)
- afinal - afinal 是一个android的 orm 和 ioc 框架。通过afinal的finalAcitivity,finalBitmap,finalDB,finalHttp,开发android应用将更加简单。 - Google Project Hosting
- android上的一个网络接口和图片缓存框架enif简析
- Android网络框架之Http请求的分发与执行
- Android HTTP网络通信(二):Volley框架——介绍、基本用法
- Android 网络请求框架android-async-http问题
- Android网络请求框架AsyncHttpClient (android-async-http)介绍说明
- Android使用动态代理搭建网络模块框架
- Android学习之——自己搭建Http框架(2)——框架扩展
- Android学习之——自己搭建Http框架(2)——框架扩展