鸿洋大神关于OKHttp教程
OKHttp源码解析
本篇博客主要是讲解一个关于okhttp的实际使用。
所以这里主要是介绍异步请求。
如果有参数首先需要拼接访问URL
/** * 获取拼接参数 * * @return String 可能为null */
public String spliceParams() {
if (!params.isEmpty()) {
StringBuilder sb = new StringBuilder();
// 拼接参数
for (Map.Entry<String, String> entry : params.entrySet()) {
sb.append(entry.getKey());
sb.append("=");
sb.append(entry.getValue());
sb.append("&");
}
// 删除最后一个多余的 &
sb = sb.delete(sb.length() - 1, sb.length());
return sb.toString();
}
return null;
}
获取完整的访问路径
/** * 获取完整访问路径 * * @param url 地址 * @return 带参数的完整路径 */
public String getCompleteUrl(String url) {
if (TextUtils.isEmpty(url))
throw new NullPointerException("url为空");
String paramsStr = spliceParams();
if (paramsStr == null) {
return url;
}
return url + "?" + paramsStr;
}
封装请求
Request.Builder builder;
builder = new Request.Builder().get().url(url);
if (tag != null) {
tags.add(tag);// 添加请求标签到集合
tagCancelFlags.put(tag, false);
builder.tag(tag);
}
进行参数封装和请求封装
FormEncodingBuilder formEncodingBuilder = new FormEncodingBuilder();
if (params != null && params.sizeOfNormal() >= 1) { // 进行非文件参数封装
for (String key : params.getKeyList()) {
formEncodingBuilder.add(key, params.getValue(key));
}
}
Request.Builder builder;
RequestBody body = formEncodingBuilder.build();
builder = new Request.Builder().post(body).url(url);
if (tag != null) {
tags.add(tag); // 添加请求标签到集合
tagCancelFlags.put(tag, false);
builder.tag(tag);
}
进行参数和请求的封装
MultipartBuilder mulBuilder = new MultipartBuilder().type(MultipartBuilder.FORM);
// 进行非文件参数封装
if (params.sizeOfNormal() >= 1) {
for (String key : params.getKeyList()) {
mulBuilder.addFormDataPart(key, params.getValue(key));
}
}
// 进行文件参数的封装
if (params.sizeOfFile() >= 1) {
for (String key : params.getFileKeys()) {
ArrayList<File> files = params.getFile(key);
for (File file : files) {
// 注意 必须指定 filename 这个参数
mulBuilder.addPart(Headers.of("Content-Disposition", "form-data; name=\""
+ key + "\"; filename=\"" + file.getName() + "\""),
RequestBody.create(MediaType.parse(mediaType), file));
}
}
}
// 请求体
RequestBody body = mulBuilder.build();
Request.Builder builder = new Request.Builder().post(body).url(url);
if (tag != null) {
tags.add(tag); // 添加请求标签到集合
tagCancelFlags.put(tag, false);
builder.tag(tag);
}
这个下载可以通过get或者post,这里主要是介绍数据的解析
/** * 从响应流里面读取文件数据 * * @param response 响应 * @param fileDir 文件目录 * @param fileName 文件名 * @param tag 请求标签 * @param mCallBack 回调 */
private void parseFile(Response response, String fileDir, String fileName, Object tag, OKHttpResultCallBack mCallBack) {
if (response.isSuccessful()) {
// 读取文件
InputStream is = null;
byte[] buffer = new byte[1024];
int len;
long currentTotalLen = 0L;
FileOutputStream fos = null;
try {
is = response.body().byteStream();
File file = new File(fileDir, fileName);
if (file.exists()) // 如果文件存在 则删除
file.delete();
fos = new FileOutputStream(file);
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
currentTotalLen += len;
sendDownProgressMessage(tag, len, currentTotalLen,
response.body().contentLength(), mCallBack);
}
fos.flush();
sendResponseMessage(tag, file.getAbsolutePath(), mCallBack);
} catch (IOException e) {
e.printStackTrace();
sendFailureMessage(tag, e, mCallBack);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
} else {
sendFailureMessage(tag, new OKResponseException(), mCallBack);
}
}
统一的发起请求的位置
// 得到Call对象 并把该对象添加带调度队列中 等待执行
/* * newCall 会得到一个Call对象 * Call是一个准备好执行的请求 可以取消 表示单个的请求/响应流 不能执行俩次 * enqueue 添加带调度队列中 等待执行 * 通常会立即执行,除非当前有正在执行的请求 * 接收一个回调 在完成或者异常时调用 * 如果在回调之前执行cancel操作不会回调 (注意回调在当前线程不在UI线程) * */
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
sendFailureMessage(tag, e, mCallBack);
}
@Override
public void onResponse(Response response) throws IOException {
if (response.isSuccessful()) {
sendResponseMessage(tag, response.body().string(), mCallBack);
} else {
sendFailureMessage(tag, new OKResponseException(), mCallBack);
}
}
});
/** * 取消请求 * * @param tag 请求标签 */
private void _cancelRequest(Object tag, OnCancelRequestHandler cancelRequestHandler) {
if (tag == null || !tags.contains(tag)) {
throw new NullPointerException("tag为空或不存在");
}
tagCancelFlags.put(tag, true); // 设置取消标记
okHttpClient.cancel(tag); // 取消请求
tags.remove(tag); // 将tag从请求标签集合里面移除
// 添加一个回调
if (cancelRequestHandler != null) {
cancelRequestHandler.onCancle();
}
}
/** * 取消全部请求 */
private void _cancelAll(OnCancelRequestHandler cancelRequestHandler) {
if (tags == null || tags.isEmpty()) {
return;
}
for (Object tag : getInstance().tags) {
okHttpClient.cancel(tag);
tagCancelFlags.put(tag, true);
}
tags.clear();
if (cancelRequestHandler != null) {
cancelRequestHandler.onCancle();
}
}
关于向自签名的网站发起请求时候,设置安全证书代码
该段代码来自 上面 鸿洋大神的博客
/** * 进行证书验证 访问https * * @param certificates 文件流 */
public void setCertificates(InputStream... certificates) {
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 ignored) {
}
}
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
sslContext.init
(
null,
trustManagerFactory.getTrustManagers(),
new SecureRandom()
);
okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
}
完整代码请查看
okhttp-library