Android中对OkHttp的封装使用
程序员文章站
2022-04-14 09:31:39
...
一、OkHttp导包:
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.okio:okio:1.9.0'
compile 'com.google.code.gson:gson:2.3.1'
二、OkHttpUtils封装成工具类:
package com.showly.okhttpdemo.http;
import android.content.Context;
import android.os.Handler;
import com.google.gson.Gson;
import com.showly.okhttpdemo.http.body.ProgressRequestBody;
import com.showly.okhttpdemo.http.body.ResponseProgressBody;
import com.showly.okhttpdemo.http.response.DownloadResponseHandler;
import com.showly.okhttpdemo.http.response.GsonResponseHandler;
import com.showly.okhttpdemo.http.response.IResponseHandler;
import com.showly.okhttpdemo.http.response.JsonResponseHandler;
import com.showly.okhttpdemo.http.response.RawResponseHandler;
import com.showly.okhttpdemo.http.util.LogUtils;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.util.Map;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* 封装好的OkHttpUtils
*/
public class OkHttpUtils {
private OkHttpClient client;
private static OkHttpUtils instance;
public OkHttpUtils() {
client = new OkHttpClient();
}
/**
* 获取句柄
* @return
*/
public static OkHttpUtils get() {
if(instance == null) {
instance = new OkHttpUtils();
}
return instance;
}
/**
* post 请求
* @param url url
* @param params 参数
* @param responseHandler 回调
*/
public void post(final String url, final Map<String, String> params, final IResponseHandler responseHandler) {
post(null, url, params, responseHandler);
}
/**
* post 请求
* @param context 发起请求的context
* @param url url
* @param params 参数
* @param responseHandler 回调
*/
public void post(Context context, final String url, final Map<String, String> params, final IResponseHandler responseHandler) {
//post builder 参数
FormBody.Builder builder = new FormBody.Builder();
if(params != null && params.size() > 0) {
for (Map.Entry<String, String> entry : params.entrySet()) {
builder.add(entry.getKey(), entry.getValue());
}
}
Request request;
//发起request
if(context == null) {
request = new Request.Builder()
.url(url)
.post(builder.build())
.build();
} else {
request = new Request.Builder()
.url(url)
.post(builder.build())
.tag(context)
.build();
}
client.newCall(request).enqueue(new MyCallback(new Handler(), responseHandler));
}
/**
* get 请求
* @param url url
* @param params 参数
* @param responseHandler 回调
*/
public void get(final String url, final Map<String, String> params, final IResponseHandler responseHandler) {
get(null, url, params, responseHandler);
}
/**
* get 请求
* @param context 发起请求的context
* @param url url
* @param params 参数
* @param responseHandler 回调
*/
public void get(Context context, final String url, final Map<String, String> params, final IResponseHandler responseHandler) {
//拼接url
String get_url = url;
if(params != null && params.size() > 0) {
int i = 0;
for (Map.Entry<String, String> entry : params.entrySet()) {
if(i++ == 0) {
get_url = get_url + "?" + entry.getKey() + "=" + entry.getValue();
} else {
get_url = get_url + "&" + entry.getKey() + "=" + entry.getValue();
}
}
}
Request request;
//发起request
if(context == null) {
request = new Request.Builder()
.url(url)
.build();
} else {
request = new Request.Builder()
.url(url)
.tag(context)
.build();
}
client.newCall(request).enqueue(new MyCallback(new Handler(), responseHandler));
}
/**
* 上传文件
* @param url url
* @param files 上传的文件files
* @param responseHandler 回调
*/
public void upload(String url, Map<String, File> files, final IResponseHandler responseHandler) {
upload(null, url, null, files, responseHandler);
}
/**
* 上传文件
* @param url url
* @param params 参数
* @param files 上传的文件files
* @param responseHandler 回调
*/
public void upload(String url, Map<String, String> params, Map<String, File> files, final IResponseHandler responseHandler) {
upload(null, url, params, files, responseHandler);
}
/**
* 上传文件
* @param context 发起请求的context
* @param url url
* @param files 上传的文件files
* @param responseHandler 回调
*/
public void upload(Context context, String url, Map<String, File> files, final IResponseHandler responseHandler) {
upload(context, url, null, files, responseHandler);
}
/**
* 上传文件
* @param context 发起请求的context
* @param url url
* @param params 参数
* @param files 上传的文件files
* @param responseHandler 回调
*/
public void upload(Context context, String url, Map<String, String> params, Map<String, File> files, final IResponseHandler responseHandler) {
MultipartBody.Builder multipartBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
//添加参数
if (params != null && !params.isEmpty()) {
for (String key : params.keySet()) {
multipartBuilder.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + key + "\""),
RequestBody.create(null, params.get(key)));
}
}
//添加上传文件
if (files != null && !files.isEmpty()) {
RequestBody fileBody;
for (String key : files.keySet()) {
File file = files.get(key);
String fileName = file.getName();
fileBody = RequestBody.create(MediaType.parse(guessMimeType(fileName)), file);
multipartBuilder.addPart(Headers.of("Content-Disposition",
"form-data; name=\"" + key + "\"; filename=\"" + fileName + "\""),
fileBody);
}
}
Request request;
if(context == null) {
request = new Request.Builder()
.url(url)
.post(new ProgressRequestBody(multipartBuilder.build(),responseHandler))
.build();
} else {
request = new Request.Builder()
.url(url)
.post(new ProgressRequestBody(multipartBuilder.build(),responseHandler))
.tag(context)
.build();
}
client.newCall(request).enqueue(new MyCallback(new Handler(), responseHandler));
}
/**
* 下载文件
* @param url 下载地址
* @param filedir 下载目的目录
* @param filename 下载目的文件名
* @param downloadResponseHandler 下载回调
*/
public void download(String url, String filedir, String filename, final DownloadResponseHandler downloadResponseHandler) {
download(null, url, filedir, filename, downloadResponseHandler);
}
/**
* 下载文件
* @param context 发起请求的context
* @param url 下载地址
* @param filedir 下载目的目录
* @param filename 下载目的文件名
* @param downloadResponseHandler 下载回调
*/
public void download(Context context, String url, String filedir, String filename, final DownloadResponseHandler downloadResponseHandler) {
Request request;
if(context == null) {
request = new Request.Builder()
.url(url)
.build();
} else {
request = new Request.Builder()
.url(url)
.tag(context)
.build();
}
client.newBuilder()
.addNetworkInterceptor(new Interceptor() { //设置拦截器
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ResponseProgressBody(originalResponse.body(), downloadResponseHandler))
.build();
}
})
.build()
.newCall(request)
.enqueue(new MyDownloadCallback(new Handler(), downloadResponseHandler, filedir, filename));
}
/**
* 取消当前context的所有请求
* @param context
*/
public void cancel(Context context) {
if(client != null) {
for(Call call : client.dispatcher().queuedCalls()) {
if(call.request().tag().equals(context))
call.cancel();
}
for(Call call : client.dispatcher().runningCalls()) {
if(call.request().tag().equals(context))
call.cancel();
}
}
}
//下载回调
private class MyDownloadCallback implements Callback {
private Handler mHandler;
private DownloadResponseHandler mDownloadResponseHandler;
private String mFileDir;
private String mFilename;
public MyDownloadCallback(Handler handler, DownloadResponseHandler downloadResponseHandler,
String filedir, String filename) {
mHandler = handler;
mDownloadResponseHandler = downloadResponseHandler;
mFileDir = filedir;
mFilename = filename;
}
@Override
public void onFailure(Call call, final IOException e) {
LogUtils.e("onFailure", e);
mHandler.post(new Runnable() {
@Override
public void run() {
mDownloadResponseHandler.onFailure(e.toString());
}
});
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
if(response.isSuccessful()) {
File file = null;
try {
file = saveFile(response, mFileDir, mFilename);
} catch (final IOException e) {
LogUtils.e("onResponse saveFile fail", e);
mHandler.post(new Runnable() {
@Override
public void run() {
mDownloadResponseHandler.onFailure("onResponse saveFile fail." + e.toString());
}
});
}
final File newFile = file;
mHandler.post(new Runnable() {
@Override
public void run() {
mDownloadResponseHandler.onFinish(newFile);
}
});
} else {
LogUtils.e("onResponse fail status=" + response.code());
mHandler.post(new Runnable() {
@Override
public void run() {
mDownloadResponseHandler.onFailure("fail status=" + response.code());
}
});
}
}
}
//callback
private class MyCallback implements Callback {
private Handler mHandler;
private IResponseHandler mResponseHandler;
public MyCallback(Handler handler, IResponseHandler responseHandler) {
mHandler = handler;
mResponseHandler = responseHandler;
}
@Override
public void onFailure(Call call, final IOException e) {
LogUtils.e("onFailure", e);
mHandler.post(new Runnable() {
@Override
public void run() {
mResponseHandler.onFailure(0, e.toString());
}
});
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
if(response.isSuccessful()) {
final String response_body = response.body().string();
if(mResponseHandler instanceof JsonResponseHandler) { //json回调
try {
final JSONObject jsonBody = new JSONObject(response_body);
mHandler.post(new Runnable() {
@Override
public void run() {
((JsonResponseHandler)mResponseHandler).onSuccess(response.code(), jsonBody);
}
});
} catch (JSONException e) {
LogUtils.e("onResponse fail parse jsonobject, body=" + response_body);
mHandler.post(new Runnable() {
@Override
public void run() {
mResponseHandler.onFailure(response.code(), "fail parse jsonobject, body=" + response_body);
}
});
}
} else if(mResponseHandler instanceof GsonResponseHandler) { //gson回调
mHandler.post(new Runnable() {
@Override
public void run() {
try {
Gson gson = new Gson();
((GsonResponseHandler)mResponseHandler).onSuccess(response.code(),
gson.fromJson(response_body, ((GsonResponseHandler)mResponseHandler).getType()));
} catch (Exception e) {
LogUtils.e("onResponse fail parse gson, body=" + response_body, e);
mResponseHandler.onFailure(response.code(), "fail parse gson, body=" + response_body);
}
}
});
} else if(mResponseHandler instanceof RawResponseHandler) { //raw字符串回调
mHandler.post(new Runnable() {
@Override
public void run() {
((RawResponseHandler)mResponseHandler).onSuccess(response.code(), response_body);
}
});
}
} else {
LogUtils.e("onResponse fail status=" + response.code());
mHandler.post(new Runnable() {
@Override
public void run() {
mResponseHandler.onFailure(0, "fail status=" + response.code());
}
});
}
}
}
//保存文件
private File saveFile(Response response, String filedir, String filename) throws IOException {
InputStream is = null;
byte[] buf = new byte[2048];
int len;
FileOutputStream fos = null;
try {
is = response.body().byteStream();
File dir = new File(filedir);
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File(dir, filename);
fos = new FileOutputStream(file);
while ((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
}
fos.flush();
return file;
} finally {
try {
if (is != null) is.close();
} catch (IOException e) {
}
try {
if (fos != null) fos.close();
} catch (IOException e) {
}
}
}
//获取mime type
private String guessMimeType(String path) {
FileNameMap fileNameMap = URLConnection.getFileNameMap();
String contentTypeFor = fileNameMap.getContentTypeFor(path);
if (contentTypeFor == null) {
contentTypeFor = "application/octet-stream";
}
return contentTypeFor;
}
}
涉及的接口及类:
1、 回调父类接口
package com.showly.okhttpdemo.http.response;
/**
* 回调接口父类
*/
public interface IResponseHandler {
void onFailure(int statusCode, String error_msg);
void onProgress(long currentBytes, long totalBytes);
}
2、 字符串结果回调接口
package com.showly.okhttpdemo.http.response;
/**
* raw 字符串结果回调
*/
public abstract class RawResponseHandler implements IResponseHandler {
public abstract void onSuccess(int statusCode, String response);
@Override
public void onProgress(long currentBytes, long totalBytes) {
}
}
3.json类型的回调接口
package com.showly.okhttpdemo.http.response;
import org.json.JSONObject;
/**
* json类型的回调接口
*/
public abstract class JsonResponseHandler implements IResponseHandler {
public abstract void onSuccess(int statusCode, JSONObject response);
@Override
public void onProgress(long currentBytes, long totalBytes) {
}
}
4.Gson类型的回调接口
package com.showly.okhttpdemo.http.response;
import com.google.gson.internal.$Gson$Types;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* Gson类型的回调接口
*/
public abstract class GsonResponseHandler<T> implements IResponseHandler {
Type mType;
public GsonResponseHandler() {
Type myclass = getClass().getGenericSuperclass(); //反射获取带泛型的class
if (myclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameter = (ParameterizedType) myclass; //获取所有泛型
mType = $Gson$Types.canonicalize(parameter.getActualTypeArguments()[0]); //将泛型转为type
}
public final Type getType() {
return mType;
}
public abstract void onSuccess(int statusCode, T response);
@Override
public void onProgress(long currentBytes, long totalBytes) {
}
}
5、下载回调接口
package com.showly.okhttpdemo.http.response;
import java.io.File;
/**
* 下载回调
*/
public abstract class DownloadResponseHandler {
public abstract void onFinish(File download_file);
public abstract void onProgress(long currentBytes, long totalBytes);
public abstract void onFailure(String error_msg);
}
6、重写request body 设置上传进度监听类
package com.showly.okhttpdemo.http.body;
import com.showly.okhttpdemo.http.response.IResponseHandler;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
import okio.Sink;
/**
* 重写request body 设置上传进度监听
*/
public class ProgressRequestBody extends RequestBody {
private IResponseHandler mResponseHandler; //回调监听
private RequestBody mRequestBody;
private BufferedSink mBufferedSink;
public ProgressRequestBody(RequestBody requestBody, IResponseHandler responseHandler) {
this.mResponseHandler = responseHandler;
this.mRequestBody = requestBody;
}
@Override
public MediaType contentType() {
return mRequestBody.contentType();
}
@Override
public long contentLength() throws IOException {
return mRequestBody.contentLength();
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
if(mBufferedSink == null) {
mBufferedSink = Okio.buffer(sink(sink));
}
//写入
mRequestBody.writeTo(mBufferedSink);
//必须调用flush,否则最后一部分数据可能不会被写入
mBufferedSink.flush();
}
/**
* 写入,回调进度接口
* @param sink Sink
* @return Sink
*/
private Sink sink(Sink sink) {
return new ForwardingSink(sink) {
//当前写入字节数
long bytesWritten = 0L;
//总字节长度,避免多次调用contentLength()方法
long contentLength = 0L;
@Override
public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
if (contentLength == 0) {
//获得contentLength的值,后续不再调用
contentLength = contentLength();
}
//增加当前写入的字节数
bytesWritten += byteCount;
//回调
mResponseHandler.onProgress(bytesWritten, contentLength);
}
};
}
}
7、重写responsebody 设置下载进度监听类
package com.showly.okhttpdemo.http.body;
import com.showly.okhttpdemo.http.response.DownloadResponseHandler;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;
/**
* 重写responsebody 设置下载进度监听
*/
public class ResponseProgressBody extends ResponseBody {
private ResponseBody mResponseBody;
private DownloadResponseHandler mDownloadResponseHandler;
private BufferedSource bufferedSource;
public ResponseProgressBody(ResponseBody responseBody, DownloadResponseHandler downloadResponseHandler) {
this.mResponseBody = responseBody;
this.mDownloadResponseHandler = downloadResponseHandler;
}
@Override
public MediaType contentType() {
return mResponseBody.contentType();
}
@Override
public long contentLength() {
return mResponseBody.contentLength();
}
@Override
public BufferedSource source() {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(mResponseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead;
@Override
public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
totalBytesRead += ((bytesRead != -1) ? bytesRead : 0);
if (mDownloadResponseHandler != null) {
mDownloadResponseHandler.onProgress(totalBytesRead, mResponseBody.contentLength());
}
return bytesRead;
}
};
}
}
三、OkHttp工具类的使用
这里演示POST、GET请求方式,以Gson解析数据类型
注:使用不同的解析方式的时候,根据需求选用不同的回调接口:GsonResponseHandler(Gson解析,返回对象数据),RawResponseHandler(返回字符串数据)、JsonResponseHandler(返回JSONObject数据)、DownloadResponseHandler(返回File数据类型)
1.Post请求(使用Gson解析数据)
Map<String, String> params = new HashMap<>();
params.put("phone", "13512345678");
OkHttpUtils.get().post(MainActivity.this, http://192.168.1.102:8066/loginapi/shortmsg/getShortMsg.do, params, new GsonResponseHandler<MobileCaptcha>() {
@Override
public void onSuccess(int statusCode, MobileCaptcha response) {
Log.i("MainActivity=22=", statusCode + "----" + response.getStatus() + "---" + response.getMsg());
}
@Override
public void onFailure(int statusCode, String error_msg) {
Log.i("MainActivity=22=", statusCode + "---" + error_msg);
}
});
2.Get请求(使用Gson解析数据)
Map<String, String> map = new HashMap<>();
map.put("phone", "13512345678");
OkHttpUtils.get().get(MainActivity.this, http://192.168.1.102:8066/loginapi/shortmsg/getShortMsg.do, map, new GsonResponseHandler<MobileCaptcha>() {
@Override
public void onSuccess(int statusCode, MobileCaptcha response) {
Log.i("MainActivity=11=", statusCode + "----" + response.getStatus() + "---" + response.getMsg());
}
@Override
public void onFailure(int statusCode, String error_msg) {
Log.i("MainActivity=11=", statusCode + "---" + error_msg);
}
});
四、这里没有说太多关于OKhttp的理论的东西,相信理论性的东西都看的很多了,直接上代码直观明了,演示Demo代码
以下是个人公众号(longxuanzhigu),之后发布的文章会同步到该公众号,方便交流学习Android知识及分享个人爱好文章:
上一篇: Eclipse不能自动编译 java文件,不会生成CLASS
下一篇: Hibernate 缓存机制
推荐阅读
-
android UI进阶之android中隐藏的layout 抽屉的使用方法
-
iOS App设计模式开发中对迭代器模式的使用示例
-
Android中ViewFlipper的使用及设置动画效果实例详解
-
Android 布局中的android:onClick的使用方法总结
-
Android 使用volley过程中遇到的问题解决办法
-
Android编程使用光线传感器获取光线强弱的方法【LightSensorManager封装类】
-
Android 中 EventBus 的使用之多线程事件处理
-
举例讲解iOS应用开发中对设计模式中的策略模式的使用
-
thinkPHP框架中layer.js的封装与使用方法示例
-
Android中对RecyclerView Adapter封装解析