Android 网络操作库 okhttp

现在Android网络方面的第三方库很多,volley,Retrofit,OKHttp等,各有各自的特点。okhttp是一款高效的HTTP客户端,支持连接同一地址的链接共享同一个socket,通过连接池来减小响应延迟,还有透明的GZIP压缩,请求缓存等优势 。

okhttp官网

githubhttps://github.com/square/okhttp

一、 使用教程

使用之前,先在在app module build.gradle配置:

compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.google.code.gson:gson:2.2.4'

1. Http Get请求

//        1. 拿到okHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient();
//        2. 构造Request对象
        Request.Builder requestBuilder = new Request.Builder();
//        Request request = requestBuilder.url("https://www.baidu.com").build();
        Request request = requestBuilder.get().url("https://www.baidu.com").build();
//        3. 将Request封装为Call
        Call call = okHttpClient.newCall(request);
//        4. 执行call
//        Response response = call.execute();     //同步
        call.enqueue(new Callback() {             //异步
            @Override
            public void onFailure(Call call, IOException e) {

            }

            /**
             * 此时还在非UI线程中
             * @param call
             * @param response
             * @throws IOException
             */
            @Override
            public void onResponse(Call call, Response response) throws IOException {
//                response.body().string();
            }
        });

2. Http Post请求

//        1. 拿到okHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient();
//        2. 构造Request对象
        FormBody.Builder fromBodyBuilder = new FormBody.Builder();
//        2.1 构造RequestBody对象
        RequestBody requestBody = fromBodyBuilder.add("mb", "19811230100").add("pwd", "999999q").build();

        Request.Builder requestBuilder = new Request.Builder();
        Request request = requestBuilder.post(requestBody).url("").build();

        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

            }
        });

3. Http Post提交Json字符串

        OkHttpClient okHttpClient = new OkHttpClient();
        RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain;chaset=utf-8"), "{mb:19811230100,pwd:123}");

        Request.Builder requestBuilder = new Request.Builder();
        Request request = requestBuilder.post(requestBody).url("").build();

        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

            }
        });
4. Http Post提交File

跟上面相比,就是RequestBody不同,如下:

Android 网络操作库 okhttp_第1张图片

5.Http Post上传文件

OkHttpClient okHttpClient = new OkHttpClient();

        File file = new File(Environment.getExternalStorageDirectory(), "test.jpg");
        if (!file.exists()) {
            Log.d("chengjie", file.getAbsolutePath() + " not exist");
            return;
        }

        MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder();
        multipartBodyBuilder.setType(MultipartBody.FORM)
                .addFormDataPart("username", "jackie")
                .addFormDataPart("password", "123")
                /**
                 * mPhoto 表单域 input标签
                 * 在服务端,通过这个表单域来获取上传的文件
                 *
                 * 这两个命名是固定的
                 * File mPhoto
                 * String mPhotoFileName
                 *
                 * if (mPhoto == null) {
                 *      System.out.println(mPhotoFileName + " is null");
                 * }
                 *
                 * String dir = ServletActionContext.getServletContext().getRealPath("files");
                 * File file = new File(dir, mPhotoFileName);
                 * FileUtils.copyFile(mPhoto, file)  //struts2封装的方法
                 */
                .addFormDataPart("mPhoto", "jackie.jpg", RequestBody.create(MediaType.parse("application/octet-stream"), file));

        RequestBody requestBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
        Request.Builder requestBuilder = new Request.Builder();
        Request request = requestBuilder.post(requestBody).url("").build();

        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

            }
        });

6.下载文件

OkHttpClient okHttpClient = new OkHttpClient();
        Request.Builder requestBuilder = new Request.Builder();
        Request request = requestBuilder.get().url("" + "test.jpg").build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //文件总长度
                long total = response.body().contentLength();
                long sum = 0L;

                InputStream is = response.body().byteStream();
                FileOutputStream fos = new FileOutputStream(new File(Environment.getExternalStorageDirectory(), "12306.jpg"));

                int len = 0;
                byte[] buf = new byte[128];
                while ((len = is.read(buf)) != -1) {
                    fos.write(buf, 0, len);

                    sum += len;

                    Log.d("chengjie", sum + "/" + total);
                }

                fos.flush();
                fos.close();
                is.close();
            }
        });

7.Session保持

Android 网络操作库 okhttp_第2张图片

8.上传文件进度

CountingRequestBody.java

package com.jackie.sample.okhttp.request;

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;

/**
 * Created by Administrator on 2016/12/16.
 */

public class CountingRequestBody extends RequestBody {
    private RequestBody mDelegate;
    private OnCountingListener mOnCountingListener;

    private CountingSink mCountingSink;

    public CountingRequestBody(RequestBody delegate, OnCountingListener onCountingListener) {
        this.mDelegate = delegate;
        this.mOnCountingListener = onCountingListener;
    }

    @Override
    public MediaType contentType() {
        return mDelegate.contentType();
    }

    @Override
    public long contentLength() {
        try {
            return mDelegate.contentLength();
        } catch (Exception e) {
            return -1;
        }
    }

    @Override
    public void writeTo(BufferedSink sink) throws IOException {
        mCountingSink = new CountingSink(sink);

        BufferedSink bufferedSink = Okio.buffer(mCountingSink);
        mDelegate.writeTo(bufferedSink);
        bufferedSink.flush();
    }

    private class CountingSink extends ForwardingSink {
        private long byteWritten;

        public CountingSink(Sink delegate) {
            super(delegate);
        }

        @Override
        public void write(Buffer source, long byteCount) throws IOException {
            super.write(source, byteCount);

            byteWritten += byteCount;
            if (mOnCountingListener != null) {
                mOnCountingListener.onRequestProgress(byteWritten, contentLength());
            }
        }
    }

    public interface OnCountingListener {
        void onRequestProgress(long byteWritten, long contentLength);
    }
}
使用方法如下:
OkHttpClient okHttpClient = new OkHttpClient();

        File file = new File(Environment.getExternalStorageDirectory(), "test.jpg");
        if (!file.exists()) {
            Log.d("chengjie", file.getAbsolutePath() + " not exist");
            return;
        }

        MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder();
        multipartBodyBuilder.setType(MultipartBody.FORM)
                .addFormDataPart("username", "jackie")
                .addFormDataPart("password", "123")
                /**
                 * mPhoto 表单域 input标签
                 * 在服务端,通过这个表单域来获取上传的文件
                 *
                 * 这两个命名是固定的
                 * File mPhoto
                 * String mPhotoFileName
                 *
                 * if (mPhoto == null) {
                 *      System.out.println(mPhotoFileName + " is null");
                 * }
                 *
                 * String dir = ServletActionContext.getServletContext().getRealPath("files");
                 * File file = new File(dir, mPhotoFileName);
                 * FileUtils.copyFile(mPhoto, file)  //struts2封装的方法
                 */
                .addFormDataPart("mPhoto", "jackie.jpg", RequestBody.create(MediaType.parse("application/octet-stream"), file))
                .build();

        RequestBody requestBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);

        CountingRequestBody countingRequestBody = new CountingRequestBody(requestBody, new CountingRequestBody.OnCountingListener() {
            @Override
            public void onRequestProgress(long byteWritten, long contentLength) {
                Log.d("chengjie", byteWritten + "/" + contentLength);
            }
        });

        Request.Builder requestBuilder = new Request.Builder();
        Request request = requestBuilder.post(requestBody).url("").build();


        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

            }
        });

二、封装

OKHttpException.java

package com.jackie.sample.okhttp.exception;

/**
 * Created by Administrator on 2016/10/30.
 */

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 Object getEmsg() {
        return emsg;
    }

    public void setEmsg(Object emsg) {
        this.emsg = emsg;
    }

    public int getEcode() {
        return ecode;
    }

    public void setEcode(int ecode) {
        this.ecode = ecode;
    }
}
DisposeDataHandler.java
package com.jackie.sample.okhttp.listener;

/**
 * Created by Administrator on 2016/10/30.
 */

public class DisposeDataHandler {
    public DisposeDataListener mListener = null;
    public Class mClazz = null;

    public DisposeDataHandler(DisposeDataListener listener) {
        mListener = listener;
    }

    public DisposeDataHandler(DisposeDataListener listener, Class clazz) {
        mListener = listener;
        mClazz = clazz;
    }
}
DisposeDataListener.java
package com.jackie.sample.okhttp.listener;

/**
 * Created by Administrator on 2016/10/30.
 */

public interface DisposeDataListener {
    void onSuccess(Object response);

    void onFailure(Object error);
}
CommonRequest.java
package com.jackie.sample.okhttp.request;

import java.io.File;
import java.util.Map;

import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.Request;
import okhttp3.RequestBody;

/**
 * Created by Administrator on 2016/10/30.
 * 负责创建各种类型的请求对象,包括get,post,文件上传类型,文件下载类型
 */

public class CommonRequest {

    /**
     * append the params to the url
     */
    public static Request createGetRequest(String url, RequestParams params) {
        StringBuilder urlBuilder = new StringBuilder(url).append("?");
        if (params != null) {
            for (Map.Entry entry : params.urlParams.entrySet()) {
                urlBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
        }

        return new Request.Builder().url(urlBuilder.substring(0, urlBuilder.length() - 1)).get().build();
    }

    /**
     * create the key-value Request
     * @param url
     * @param params
     * @return
     */
    public static Request createPostRequest(String url, RequestParams params) {
        FormBody.Builder builder = new FormBody.Builder();
        if (params != null) {
            for (Map.Entry entry : params.urlParams.entrySet()) {
                builder.add(entry.getKey(), entry.getValue());
            }
        }

        FormBody body = builder.build();
        return new Request.Builder().url(url).post(body).build();
    }

    /**
     * 文件上传请求
     */
    private static final MediaType FILE_TYPE = MediaType.parse("application/octet-stream");

    public static Request createMultiPostRequest(String url, RequestParams params) {
        MultipartBody.Builder builder = new MultipartBody.Builder();
        builder.setType(MultipartBody.FORM);
        if (params != null) {
            for (Map.Entry entry : params.fileParams.entrySet()) {
                if (entry.getValue() instanceof File) {
                    builder.addPart(MultipartBody.Part.createFormData(entry.getKey(),
                            null,
                            RequestBody.create(FILE_TYPE, (File) entry.getValue())));
                } else {
                    builder.addFormDataPart(entry.getKey(), String.valueOf(entry.getValue()));
                }
            }
        }
        return new Request.Builder().url(url).post(builder.build()).build();
    }
}
RequestParams.java
package com.jackie.sample.okhttp.request;

import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by Administrator on 2016/10/30.
 */

public class RequestParams {
    public ConcurrentHashMap urlParams = new ConcurrentHashMap<>();
    public ConcurrentHashMap fileParams = new ConcurrentHashMap<>();

    /**
     * Constructs a new empty { @code RequestParams } instance.
     */
    public RequestParams() {
        this((Map) null);
    }

    /**
     * Constructs a new RequestParams instance containing the key/value string
     * params from this specified map.
     *
     * @param source
     *           the source key/value string map to add.
     */
    public RequestParams(Map source) {
        if (source != null) {
            for (Map.Entry entry : source.entrySet()) {
                put(entry.getKey(), entry.getValue());
            }
        }
    }

    public void put(String key, String value) {
        urlParams.put(key, value);
    }

    public void put(String key, File file) {
        fileParams.put(key, file);
    }
}
CommonJsonCallback.java
package com.jackie.sample.okhttp.response;

import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;

import com.google.gson.Gson;
import com.jackie.sample.okhttp.exception.OkHttpException;
import com.jackie.sample.okhttp.listener.DisposeDataHandler;
import com.jackie.sample.okhttp.listener.DisposeDataListener;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

/**
 * Created by Administrator on 2016/10/30.
 */

/**
 * 专门处理Json的回调
 */
public class CommonJsonCallback implements Callback {
    /**
     * the logic layer exception, may alter in different app
     */
    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 = "";

    /**
     * the java layer exception, do not same to the logic error
     */
    protected final int NETWORK_ERROR = -1;  //the network relative error
    protected final int JSON_ERROR = -2;  //the json relative error
    protected final int OTHER_ERROR = -3;  //the unknown error

    private DisposeDataListener mListener;
    private Class mClazz;
    private Handler mHandler;

    public CommonJsonCallback(DisposeDataHandler handler) {
        mListener = handler.mListener;
        mClazz = handler.mClazz;
        mHandler = new Handler(Looper.getMainLooper());
    }

    @Override
    public void onFailure(Call call, final IOException e) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (mListener != null) {
                    mListener.onFailure(e);
                }
            }
        });
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        //还在子线程中
        final String result = response.body().toString();
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                handleResponse(result);
            }
        });
    }

    private void handleResponse(String result) {
        if (TextUtils.isEmpty(result)) {
            if (mListener != null) {
                mListener.onFailure(new OkHttpException(NETWORK_ERROR, EMPTY_MSG));
                return;
            }
        }

        try {
            JSONObject resultJsonObject = new JSONObject(result);
            if (resultJsonObject.has(RESULT_CODE)) {
                if (resultJsonObject.optInt(RESULT_CODE) == RESULT_CODE_VALUE) {
                    if (mClazz == null) {
                        if (mListener != null) {
                            mListener.onSuccess(resultJsonObject);
                        }
                    } else {
                        Gson gson = new Gson();
                        Object resultObject = gson.fromJson(result, mClazz);

                        if (resultObject == null) {
                            if (mListener != null) {
                                mListener.onFailure(new OkHttpException(JSON_ERROR, EMPTY_MSG));
                            }
                        } else {
                            //相应真正正确的处理,并且直接返回了实体对象
                            if (mListener != null) {
                                mListener.onSuccess(resultObject);
                            }
                        }
                    }
                }
            } else {
                if (mListener != null) {
                    mListener.onFailure(new OkHttpException(NETWORK_ERROR, EMPTY_MSG));
                }
            }
        } catch (JSONException e) {
            if (mListener != null) {
                mListener.onFailure(new OkHttpException(OTHER_ERROR, e.getMessage()));
            }
        }
    }
}
CommonOkHttpClient.java
package com.jackie.sample.okhttp;

/**
 * Created by Administrator on 2016/10/30.
 */

import com.jackie.sample.okhttp.listener.DisposeDataHandler;
import com.jackie.sample.okhttp.response.CommonJsonCallback;

import java.security.NoSuchAlgorithmException;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;

import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;

/**
 * 用来发送get,post请求的工具类,包括设置一些请求的公用参数
 */
public class CommonOkHttpClient {
    private static final int TIME_OUT = 30;
    private static OkHttpClient mOkHttpClient;

    static {
        OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder();
        //对https的认证
        okHttpBuilder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String s, SSLSession sslSession) {
             return true;
          }
        });

        try {
            okHttpBuilder.connectTimeout(TIME_OUT, TimeUnit.SECONDS);
            okHttpBuilder.readTimeout(TIME_OUT, TimeUnit.SECONDS);
            okHttpBuilder.writeTimeout(TIME_OUT, TimeUnit.SECONDS);
            okHttpBuilder.followRedirects(true);

            SSLContext sslContext = SSLContext.getInstance("TLS");
            okHttpBuilder.sslSocketFactory(sslContext.getSocketFactory());

            mOkHttpClient = okHttpBuilder.build();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    public static void get(Request request, DisposeDataHandler handler) {
        Call call = mOkHttpClient.newCall(request);
        call.enqueue(new CommonJsonCallback(handler));
    }

    public static void post(Request request, DisposeDataHandler handler) {
        Call call = mOkHttpClient.newCall(request);
        call.enqueue(new CommonJsonCallback(handler));
    }
}
封装之后代码结构图如下:

Android 网络操作库 okhttp_第3张图片
封装之后,网络请求就简单多了,如下图:

Get请求

Android 网络操作库 okhttp_第4张图片

Post请求

Android 网络操作库 okhttp_第5张图片Android 网络操作库 okhttp_第6张图片








你可能感兴趣的:(Android开源框架)