版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Adonis044/article/details/82118456
1.OKHttp基本使用方法
使用OkHttp发送一个最基本的网络请求,代码如下:
//okhttp发送一个基本请求
private void sendRequest() {
//创建okhttpClient对象
OkHttpClient mOkHttpClient = new OkHttpClient();
//创建一个Request
final Request request = new Request.Builder()
.url("https://www.baidu.com")
.build();
//new call
Call call = mOkHttpClient.newCall(request);
//请求加入调度
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
}
可以看到,这么长的代码在项目中使用是极为不方便的,况且是不可能在每一处需要进行网络请求的地方都写上这么长的相同的一串代码上去。就算你复制粘贴,代码的冗余度太高,效率低,没有美感。所以需要我们自己封装。
2.OKHttp结构框架
- request:为我们创建请求参数
- okhttpclient:发送请求
- callback:处理回调
所以OKHttp框架的结构如图:
我们需要将OKHttp分成三部分进行理解和封装。
3.request的封装
request的主要作用:
- 接收请求参数
- 为我们创建好请求对象
3.1封装所有的请求参数到hashmap中
代码如下:
public class RequestParams {
//创建两个线程安全的hashmap
public ConcurrentHashMap<String, String> urlParams = new ConcurrentHashMap<String, String>();
public ConcurrentHashMap<String, Object> fileParams = new ConcurrentHashMap<String, Object>();
public void put(String key, String value) {
if (key != null && value != null) {
urlParams.put(key, value);
}
}
public void put(String key, Object object) throws FileNotFoundException {
if (key != null) {
fileParams.put(key, object);
}
}
public boolean hasParams() {
if (urlParams.size() > 0 || fileParams.size() > 0) {
return true;
}
return false;
}
}
主要目的是创建两个线程安全的hashmap将需要的请求参数放入其中,完成对请求参数的封装。
3.2接受请求参数,生成Request对象
代码如下:
public class CommonRequest {
/**
* @param url
* @param params 接收的参数
* @return 返回一个创建好的Request对象
*/
public static Request createPostRequest(String url, RequestParams params) {
//生成一个Request(post类型)
//构建者模式,构建一个FormBody
FormBody.Builder mFormBodyBuild = new FormBody.Builder();
if (params != null) {
for (Map.Entry<String, String> entry : params.urlParams.entrySet()) {
//将请求参数逐一遍历添加到我们的请求构建类中
mFormBodyBuild.add(entry.getKey(), entry.getValue());
}
}
//生成请求对象,FormBody对象是真正的请求体。
// 通过请求构建类的build方法获取到真正的请求体对象
FormBody mFormBody = mFormBodyBuild.build();
//返回一个构建好的Request对象
return new Request.Builder().url(url).post(mFormBody).build();
}
/**
* @param url
* @param params
* @return 通过传入的参数,返回一个Get类型的请求
*/
public static Request createGetRequest(String url, RequestParams params) {
//字符串拼接,使用String Builder效率更高
//Get请求就是url ? 后面带参数
StringBuilder urlBuilder = new StringBuilder(url).append("?");
if (params != null) {
for (Map.Entry<String, String> entry : params.urlParams.entrySet()) {
//参数拼接
urlBuilder.append(entry.getKey()).append("=").
append(entry.getValue()).append("&");
}
}
//返回一个构建好的Request对象
return new Request.Builder().url(urlBuilder.substring(0, urlBuilder.length() - 1)).
get().build();
}
}
- 先建立FormBody的构建者,然后通过刚才对参数的封装从中逐个遍历取出请求参数将其添加到我们的请求构建类中。
- 通过请求构建类生成请求对象。
- 返回一个构建好的Request对象
GET类型请求还是一个道理,只不过需要将参数拼接到url?
后面,最后还是返回一个构建好的Request对象。
4.callback的封装
callback的主要作用:
- 处理回调函数
- 异常处理
- 转发消息到我们的UI线程
- 将JSON转化为对应的实体
4.1自定义事件监听DisposeDataListener
为了减少依赖性和防止OKHttp框架的改动对我们代码造成的影响,我们在这里自定义事件监听,代码如下:
public interface DisposeDataListener {
/**
* 请求成功回调事件处理
*/
public void onSuccess(Object responseObj);
/**
* 请求失败回调事件处理
*/
public void onFailure(Object reasonObj);
}
4.2封装响应回调和要转换的字节码
public class DisposeDataHandle {
public DisposeDataListener mListener = null;
public Class<?> mClass = null;
public DisposeDataHandle(DisposeDataListener mListener) {
this.mListener = mListener;
}
public DisposeDataHandle(DisposeDataListener mListener, Class<?> mClass) {
this.mListener = mListener;
this.mClass = mClass;
}
}
将响应回调和要转换的字节码进行封装,如果不需要转换成相应的实体类,就不处理继续上抛
4.3专门处理JSON的回调响应
public class CommonJsonCallback implements Callback {
//与服务器返回的字段的一个对应关系
protected final String RESULT_CODE = "ecode";//有返回则对http请求来说是成功的
protected final int RESULT_CODE_VALUE = 0;
protected final String ERROR_MSG = "emsg";
protected final String EMPTY_MSG = "";
/**
* 自定义异常类型
*/
protected final int NETWORK_ERROR = -1;
protected final int JSON_ERROR = -2;
protected final int OTHER_ERROR = -3;//the unknow error
private Handler mDeliverHandler;//进行消息的转发,子线程转换UI线程
private DisposeDataListener mListener;//回调
private Class<?> mClass;//要转换的字节码
public CommonJsonCallback(DisposeDataHandle handle) {
this.mListener = handle.mListener;
this.mClass = handle.mClass;
this.mDeliverHandler = new Handler(Looper.getMainLooper());
}
/**
* 请求失败处理
* @param call
* @param e
*/
@Override
public void onFailure(Call call, final IOException e) {
//异常抛出到应用层
//转发消息到主线程
mDeliverHandler.post(new Runnable() {
@Override
public void run() {
mListener.onFailure(new OkHttpException(NETWORK_ERROR, e));
}
});
}
//服务器有相应,真正的响应处理函数
@Override
public void onResponse(Call call, Response response) throws IOException {
//JSON处理,返回的肯定是字符串
//拿到响应体中的信息
final String result = response.body().string();
mDeliverHandler.post(new Runnable() {
@Override
public void run() {
handleResponse(result);
}
});
}
/**
* 处理服务器返回的请求数据
*
* @param responseObj
*/
private void handleResponse(Object responseObj) {
Gson gson = new Gson();
//保证健壮性
if (responseObj == null && responseObj.toString().trim().equals("")) {
mListener.onFailure(new OkHttpException(NETWORK_ERROR, EMPTY_MSG));
return;
}
try {
//接收参数
JSONObject result = new JSONObject(responseObj.toString());
//开始尝试解析JSON
if (result.has(RESULT_CODE)) {
//从JSON对象中取出响应码,若为0则正确(自己和服务器商定)
if (result.getInt(RESULT_CODE) == RESULT_CODE_VALUE) {
//不需要解析,直接返回数据到应用层
if (mClass == null) {
mListener.onSuccess(responseObj);
} else {
//即,需要将JSON对象转化为实体对象
Object obj = gson.fromJson(String.valueOf(result), mClass);
//正确转化了实体对象
if (obj != null) {
mListener.onSuccess(obj);
} else {
//返回的是不合法的json
mListener.onFailure(new OkHttpException(JSON_ERROR, EMPTY_MSG));
}
}
} else {
//将服务器返回给我们的异常回调到应用去处理
mListener.onFailure(new OkHttpException(OTHER_ERROR, result.get(RESULT_CODE)));
}
}
} catch (Exception e) {
mListener.onFailure(new OkHttpException(OTHER_ERROR, e.getMessage()));
}
}
}
其中我们自定义了一个异常类
public class OkHttpException extends Exception {
private static final long serialVersionUID = 1L;
/**
* the server return code
*/
private int ecode;
/**
* the server return error message
*/
private Object emsg;
public OkHttpException(int ecode, Object emsg) {
this.ecode = ecode;
this.emsg = emsg;
}
public int getEcode() {
return ecode;
}
public Object getEmsg() {
return emsg;
}
}
5.OKHttpClient的封装
okhttpclient主要作用:
- 发送GET/POST请求
- 请求相关参数设置
- https支持
代码如下:
public class CommonOkHttpClient {
private static final int TIME_OUT = 30;//超时参数
private static OkHttpClient mOkHttpClient;
//为我们的client去配置参数,静态语句块导致所有参数都一致
static {
//创建client对象的构建者
OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder();
//为构建者填充参数,超时时间
okHttpBuilder.connectTimeout(TIME_OUT, TimeUnit.SECONDS);
okHttpBuilder.readTimeout(TIME_OUT, TimeUnit.SECONDS);
okHttpBuilder.writeTimeout(TIME_OUT, TimeUnit.SECONDS);
//允许请求重定向
okHttpBuilder.followRedirects(true);
//添加https支持
okHttpBuilder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
//什么证书都支持,所有无论什么,都返回true
return true;
}
});
okHttpBuilder.sslSocketFactory(HttpsUtils.getSslSocketFactory());//https支持
//配置完成,生成client对象
mOkHttpClient = okHttpBuilder.build();
}
/**
* 发送具体的HTTP/https请求
*
* @param request
* @param commCallback
* @return Call
*/
public static Call sendRequest(Request request, CommonJsonCallback commCallback) {
Call call = mOkHttpClient.newCall(request);
call.enqueue(commCallback);
return call;
}
public static Call get(Request request, DisposeDataHandle handle) {
Call call = mOkHttpClient.newCall(request);
call.enqueue(new CommonJsonCallback(handle));
return call;
}
public static Call post(Request request, DisposeDataHandle handle) {
Call call = mOkHttpClient.newCall(request);
call.enqueue(new CommonJsonCallback(handle));
return call;
}
}
这里为了支持https,我参考了洪洋的okhttp完全解析,在其中创建一个工具类支持sslsocket,设计一些加密和信任管理的知识,代码如下:
public class HttpsUtils {
public static SSLSocketFactory getSslSocketFactory(InputStream[] certificates, InputStream bksFile, String password) {
try {
TrustManager[] trustManagers = prepareTrustManager(certificates);
KeyManager[] keyManagers = prepareKeyManager(bksFile, password);
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(keyManagers, new TrustManager[]
{new MyTrustManager(chooseTrustManager(trustManagers))}, new SecureRandom());
return sslContext.getSocketFactory();
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
} catch (KeyManagementException e) {
throw new AssertionError(e);
} catch (KeyStoreException e) {
throw new AssertionError(e);
}
}
private static TrustManager[] prepareTrustManager(InputStream... certificates) {
if (certificates == null || certificates.length <= 0)
return null;
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
int index = 0;
for (InputStream certificate : certificates) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
try {
if (certificate != null)
certificate.close();
} catch (IOException e)
{
}
}
TrustManagerFactory trustManagerFactory = null;
trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
return trustManagers;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static KeyManager[] prepareKeyManager(InputStream bksFile, String password) {
try {
if (bksFile == null || password == null)
return null;
KeyStore clientKeyStore = KeyStore.getInstance("BKS");
clientKeyStore.load(bksFile, password.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, password.toCharArray());
return keyManagerFactory.getKeyManagers();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static X509TrustManager chooseTrustManager(TrustManager[] trustManagers) {
for (TrustManager trustManager : trustManagers) {
if (trustManager instanceof X509TrustManager) {
return (X509TrustManager) trustManager;
}
}
return null;
}
public static SSLSocketFactory getSslSocketFactory() {
initTrustManager();
return initSSLSocketFactory();
}
private static class MyTrustManager implements X509TrustManager {
private X509TrustManager defaultTrustManager;
private X509TrustManager localTrustManager;
public MyTrustManager(X509TrustManager localTrustManager) throws NoSuchAlgorithmException, KeyStoreException {
TrustManagerFactory var4 = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
var4.init((KeyStore) null);
defaultTrustManager = chooseTrustManager(var4.getTrustManagers());
this.localTrustManager = localTrustManager;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
try {
defaultTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException ce) {
localTrustManager.checkServerTrusted(chain, authType);
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
/**
* 创建加密上下文
*
* @return
*/
public static SSLSocketFactory initSSLSocketFactory() {
SSLContext sslContext = null;
try {
//和服务器算法保持一致"SSL"
sslContext = SSLContext.getInstance("SSL");
X509TrustManager[] xTrustArray = new X509TrustManager[]
{initTrustManager()};
//初始化加密上下文
sslContext.init(null,
xTrustArray, new SecureRandom());
} catch (Exception e) {
e.printStackTrace();
}
return sslContext.getSocketFactory();
}
/**
* 1.生成一个信任管理器类
*/
public static X509TrustManager initTrustManager() {
//https使用的协议
X509TrustManager mTrustManager = new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
};
return mTrustManager;
}
}
6.总结
经过我们的封装,现在进行网络请求只需这样写:
private void test() {
CommonOkHttpClient.sendRequest(CommonRequest.
createGetRequest("http://www.baidu.com", null), new CommonJsonCallback(new DisposeDataHandle(new DisposeDataListener() {
@Override
public void onSuccess(Object responseObj) {
}
@Override
public void onFailure(Object reasonObj) {
}
})));
}