封装 OkHttp 框架,主要功能有:
GET 请求
POST FORM
POST JSON
封装之前,再次熟悉一下 OkHttp 请求网络的大致步骤,让封装的时候思路清晰一点。
//1、初始化 OkHttpClient 对象
private OkHttpClient mHttpClient = new OkHttpClient();
//2、构造Request
//2.1 构造RequestBody
FormEncodingBuilder builder = new FormEncodingBuilder();
RequestBody requestBody = builder.add("key", "value").build();
final Request request = new Request
.Builder()
.post(requestBody)
.url(url)
.build();
//3、将 Request 封装成 call
final Call call = mHttpClient.newCall(request);
//4、执行 call
call.enqueue(new Callback() {
//请求失败调用
@Override
public void onFailure(Request request, IOException e) {
}
//请求成功调用
@Override
public void onResponse(Response response) throws IOException {
}
});
OkHttp 请求基本步骤就是这几步,看起来很简单,要封装自然也要考虑到这里面的方方面面,根据自己的业务需求进行相应的封装。封装是基于鸿洋大神的 OkHttpUtils,站在巨人的肩膀上,我们封装起来会更加简单。
1、OkHttpClient 实例化
声明一个私有的 OkHttpClient 对象,对其进行构建并设置超时信息,而 AsyncHttp 类则是我们要进行网络访问对外公开的类,OkHttpClient 官方建议我们设置成单例模式。
public class AsyncHttp {
private static AsyncHttp mInstance;
//初始化操作,设置超时时间
private OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(20 * 1000, TimeUnit.MILLISECONDS)
.readTimeout(20 * 1000, TimeUnit.MILLISECONDS)
.build();
//私有构造函数,初始化 OkHttpClient 对象
private AsyncHttp() {
OkHttpUtils.initClient(okHttpClient);
}
//单例模式
public static AsyncHttp instance() {
if (mInstance == null) {
synchronized (OkHttpUtils.class) {
if (mInstance == null) {
mInstance = new AsyncHttp();
}
}
}
return mInstance;
}
}
2、构造 GET 请求
get 请求官方给我们的是没有参数的,不满足我们需求,根据我们的需求将其进行封装。GET 请求需要 Request 对象传参,还需要回调 CallBack,因此需要添加 Request 基类和 CallBack 基类。
public void get(IRequest request, IHttpListener listener) {}
IRequest 是 Request 的封装类,IHttpListener 是回调 CallBack 的监听。
2.1、封装 IRequest
我们知道官方提供的 Request 类是对请求信息进行封装,包括请求地址 url,请求方法 method,请求头 head,请求体 RequestBody,取消 http 请求的标志 tag。IRequest 是一个抽象类,请求信息封装在 RequestParams 类里面,IRequest 对外提供了一些方法,获取请求参数,获取/设置唯一标识,获取 Url,获取解析的数据类型。
//IDontObfuscate 实现 Serializable 的一个抽象类
public abstract class IRequest extends IDontObfuscate {
//测试登录的 API
public static final String HOST_PUBLIC = "http://live.demo.cniao5.com/Api/";
public static final String HOST_DEBUG = "http://192.168.31.92:8094/Api/";
//判断上面两个 API 使用哪一个。表示猜不透直播老师的心啊,不知道为什么要这样
private boolean DEBUG = false;
//Request 请求信息封装类
protected RequestParams mParams = new RequestParams();
//请求网络直播登录的唯一标识
public int mRequestId = 0;
protected int mDraw = 0;
public IRequest() {
}
/**
* 接口请求参数
*/
public RequestParams getParams() {
return mParams;
}
/**
* 设置接口请求唯一标识
*/
public void setRequestId(int requestId) {
mRequestId = requestId;
}
/**
* 返回请求接口唯一标识
*/
public int getRequestId() {
return mRequestId;
}
/**
* 当前接口的url地址
*/
public abstract String getUrl();
/**
* 获取解析类型
*/
public abstract Type getParserType();
/**
* 返回服务器接口地址
*/
protected String getHost() {
return DEBUG ? HOST_DEBUG : HOST_PUBLIC;
}
@Override
public String toString() {
return "IRequest [DEBUG=" + DEBUG
+ ", mParams=" + mParams + ", mRequestId=" + mRequestId
+ ", mDraw=" + mDraw + "]";
}
//是否缓存
public boolean isCache() {
return false;
}
}
RequestParams 请求参数封装
参数封装类,顾名思义就是对参数的保存和移除,该类适用于 GET 和 POST 参数,包括 url 参数封装,stream 参数封装,file 参数封装,file 数组参数封装,url 对象参数封装。全部都是存储在 ConcurrentHashMap 对象中,通过键值对进行存储,put 方法有很多重载,对不同形式的参数采取不同的添加方式。
public class RequestParams implements Serializable{
//二进制流数据
public final static String APPLICATION_OCTET_STREAM = "application/octet-stream";
//JSON数据格式
public final static String APPLICATION_JSON = "application/json";
protected final static String LOG_TAG = "RequestParams";
//存储 url 参数
protected final ConcurrentHashMap<String, String> urlParams = new ConcurrentHashMap<String, String>();
//存储 stream 参数
protected final ConcurrentHashMap<String, StreamWrapper> streamParams = new ConcurrentHashMap<String, StreamWrapper>();
//存储 file 参数
protected final ConcurrentHashMap<String, FileWrapper> fileParams = new ConcurrentHashMap<String, FileWrapper>();
//存储 fileArray 参数
protected final ConcurrentHashMap<String, List<FileWrapper>> fileArrayParams = new ConcurrentHashMap<String, List<FileWrapper>>();
//存储 url 对象参数
protected final ConcurrentHashMap<String, Object> urlParamsWithObjects = new ConcurrentHashMap<String, Object>();
//是否重复
protected boolean isRepeatable;
//标志 multipart/form-data:需要在表单中进行文件上传时,就需要使用该格式
protected boolean forceMultipartEntity = false;
//用户 json 数据流
protected boolean useJsonStreamer;
//自动关闭输入流标志
protected boolean autoCloseInputStreams;
//保存上传有效载荷所需的时间
protected String elapsedFieldInJsonStreamer = "_elapsed";
//指定编码格式
protected String contentEncoding = "utf-8";
private Gson mGson = new Gson();
/**
* 构造一个空的 RequestParams 实例
*/
public RequestParams() {
this((Map<String, String>) null);
}
//获取 urlParams
public String getUrlParams(String key){
if(!TextUtils.isEmpty(key)&&urlParams.containsKey(key)){
return urlParams.get(key);
}
return "";
}
/**
* 构造一个新的RequestParams实例,该实例包含指定map中的键/值字符串参数。
*/
public RequestParams(Map<String, String> source) {
if (source != null) {
for (Map.Entry<String, String> entry : source.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
}
/**
* 构造一个新的RequestParams实例,并使用单个初始键/值填充
*/
public RequestParams(final String key, final String value) {
this(new HashMap<String, String>() {{
put(key, value);
}});
}
/**
* 构造一个新的RequestParams实例,并用多个初始键/值填充
*/
public RequestParams(Object... keysAndValues) {
int len = keysAndValues.length;
if (len % 2 != 0)
throw new IllegalArgumentException("Supplied arguments must be even");
for (int i = 0; i < len; i += 2) {
String key = String.valueOf(keysAndValues[i]);
String val = String.valueOf(keysAndValues[i + 1]);
put(key, val);
}
}
public void setContentEncoding(final String encoding) {
if (encoding != null) {
this.contentEncoding = encoding;
} else {
Log.d(LOG_TAG, "setContentEncoding called with null attribute");
}
}
/**
* 如果设置为true,即使没有文件或流被发送,也会将Content-Type头部强制为“multipart/form-data”
* multipart/form-data:需要在表单中进行文件上传时,就需要使用该格式
*/
public void setForceMultipartEntityContentType(boolean force) {
this.forceMultipartEntity = force;
}
/**
* 添加 string 类型字符串到 urlParams
*/
public void put(String key, String value) {
if (key != null && value != null) {
urlParams.put(key, value);
}
}
/**
* 将自定义提供的文件内容类型和文件名称添加到 fileArrayParams
*/
public void put(String key, File files[]) throws FileNotFoundException {
put(key, files, null, null);
}
/**
* 将自定义提供的文件内容类型和文件名称添加到 fileArrayParams
*/
public void put(String key, File files[], String contentType, String customFileName) throws FileNotFoundException {
if (key != null) {
List<FileWrapper> fileWrappers = new ArrayList<FileWrapper>();
for (File file : files) {
if (file == null || !file.exists()) {
throw new FileNotFoundException();
}
fileWrappers.add(new FileWrapper(file, contentType, customFileName));
}
fileArrayParams.put(key, fileWrappers);
}
}
/**
* 将自定义提供的文件内容类型和文件名添加到 fileParams
*/
public void put(String key, File file) throws FileNotFoundException {
put(key, file, null, null);
}
/**
* 将自定义提供的文件内容类型和文件名添加到 fileParams
*/
public void put(String key, String customFileName, File file) throws FileNotFoundException {
put(key, file, null, customFileName);
}
/**
* 将自定义提供的文件内容类型和文件名添加到 fileParams
*/
public void put(String key, File file, String contentType) throws FileNotFoundException {
put(key, file, contentType, null);
}
/**
* 将自定义提供的文件内容类型和文件名添加到 fileParams
*/
public void put(String key, File file, String contentType, String customFileName) throws FileNotFoundException {
if (file == null || !file.exists()) {
throw new FileNotFoundException();
}
if (key != null) {
fileParams.put(key, new FileWrapper(file, contentType, customFileName));
}
}
/**
* 添加 InputStream 流到 streamParams
*/
public void put(String key, InputStream stream) {
put(key, stream, null);
}
/**
* 添加 InputStream 流到 streamParams
*/
public void put(String key, InputStream stream, String name) {
put(key, stream, name, null);
}
/**
* 添加 InputStream 流到 streamParams
*/
public void put(String key, InputStream stream, String name, String contentType) {
put(key, stream, name, contentType, autoCloseInputStreams);
}
/**
* 添加 InputStream 流到 streamParams
*/
public void put(String key, InputStream stream, String name, String contentType, boolean autoClose) {
if (key != null && stream != null) {
streamParams.put(key, StreamWrapper.newInstance(stream, name, contentType, autoClose));
}
}
/**
* 添加 Object 对象到 urlParamsWithObjects
*/
public void put(String key, Object value) {
if (key != null && value != null) {
urlParamsWithObjects.put(key, value);
}
}
/**
* 添加 int 类型字符串到 urlParams
*/
public void put(String key, int value) {
if (key != null) {
urlParams.put(key, String.valueOf(value));
}
}
/**
* 添加 long 类型字符串到 urlParams
*/
public void put(String key, long value) {
if (key != null) {
urlParams.put(key, String.valueOf(value));
}
}
/**
* 添加 String 类型字符串到 urlParamsWithObjects
*/
public void add(String key, String value) {
if (key != null && value != null) {
Object params = urlParamsWithObjects.get(key);
if (params == null) {
// 向后兼容,这将导致“k = v1&k = v2&k = v3”
params = new HashSet<String>();
this.put(key, params);
}
if (params instanceof List) {
((List<Object>) params).add(value);
} else if (params instanceof Set) {
((Set<Object>) params).add(value);
}
}
}
/**
* 从 request 中移除某个字段
*/
public void remove(String key) {
urlParams.remove(key);
streamParams.remove(key);
fileParams.remove(key);
urlParamsWithObjects.remove(key);
fileArrayParams.remove(key);
}
/**
* 监测字段是否被定义
*/
public boolean has(String key) {
return urlParams.get(key) != null ||
streamParams.get(key) != null ||
fileParams.get(key) != null ||
urlParamsWithObjects.get(key) != null ||
fileArrayParams.get(key) != null;
}
public void setHttpEntityIsRepeatable(boolean flag) {
this.isRepeatable = flag;
}
public void setUseJsonStreamer(boolean flag) {
this.useJsonStreamer = flag;
}
/**
* 通过流上传 JSON 对象时设置一个附加字段,以保存上载有效载荷所需的时间(以毫秒为单位)。 默认情况下,此字段设置为“_elapsed”。
* 要禁用此功能,请将此方法调用为null作为字段值。
*/
public void setElapsedFieldInJsonStreamer(String value) {
this.elapsedFieldInJsonStreamer = value;
}
/**
* 设置全局标志,用于确定在成功上传时是否自动关闭输入流。
*/
public void setAutoCloseInputStreams(boolean flag) {
autoCloseInputStreams = flag;
}
/**
* http get builder 参数封装构造类
*/
public GetBuilder getGetBuilder() {
GetBuilder getBuilder = new GetBuilder();
//添加参数 url 后面
for (ConcurrentHashMap.Entry<String, String> entry : urlParams.entrySet()) {
Log.i("log", "getBuilder value:" + entry.getValue());
getBuilder.addParams(entry.getKey(), entry.getValue());
}
return getBuilder;
}
/**
* post form 表单
*/
public PostFormBuilder getPostFormBuilder() {
PostFormBuilder postFormBuilder = new PostFormBuilder();
// post 请求添加参数 url后面添加
for (ConcurrentHashMap.Entry<String, String> entry : urlParams.entrySet()) {
Log.i("log", "getBuilder value:" + entry.getValue());
postFormBuilder.addParams(entry.getKey(), entry.getValue());
}
//post 请求添加参数 file 文件参数
for (ConcurrentHashMap.Entry<String, FileWrapper> entry : fileParams.entrySet()) {
postFormBuilder.addFile(entry.getKey(), entry.getValue().file.getAbsolutePath(), entry.getValue().file);
}
//文件对象列表存储相关信息
//public PostFormBuilder addFile(String name, String filename, File file)
//{
// files.add(new FileInput(name, filename, file));
// return this;
本文作者为菜鸟窝编辑蒋志碧
添加菜鸟窝运营微信:yrioyou备注【菜鸟直播】入群学习
微信图片_20170803172638.jpg关注菜鸟窝官网,免费领取“140套开源项目”
微信图片_20170813151906.jpg 微信图片_20170813151919.jpg
网友评论