Android中對OkHttp的封裝使用
阿新 • • 發佈:2018-12-09
一、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);
}
- 字串結果回撥介面
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的理論的東西,相信理論性的東西都看的很多了,直接上程式碼直觀明瞭。
以下是個人公眾號(longxuanzhigu),之後釋出的文章會同步到該公眾號,方便交流學習Android知識及分享個人愛好文章: