1. 程式人生 > >Android中對OkHttp的封裝使用

Android中對OkHttp的封裝使用

一、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);
}
  1. 字串結果回撥介面
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知識及分享個人愛好文章: 這裡寫圖片描述