Okhttp is pretty familiar, but without a good wrapper, you write a lot of redundant code every time, and if okHTTP is no longer used in future projects, the application layer will need to be changed a lot, so it’s not maintained well and needs to be wrapped well. The effect achieved after encapsulation is as follows:

  • Send the request with a invocation of one line of code
  • Custom callback, which handles callback results, can convert JSON into entity classes
  • Support HTTPS

Let’s take a look at the results:

Before wrapping, I need to comb through my okHTTP knowledge. I drew a diagram:

The three core elements of OKHTTP are Request, okHttpClient, and callBack. A request can take some parameters, send a request to the server via okHttpClient, and callback data or exception information via callback. Therefore, when packaging, we should also consider these three points, observe the similarities and differences, so as to carry out packaging

Typically, okHTTP sends a GET request like this:

// Create okHttpClient object
OkHttpClient mOkHttpClient = new OkHttpClient();
// Create a Request
final Request request = new Request.Builder()
                .url("https://github.com/")
                .build();
//new call
Call call = mOkHttpClient.newCall(request);
// Request to join the schedule
call.enqueue(new Callback()
        {
            @Override
            public void onFailure(Request request, IOException e)
            {
            }
            @Override
            public void onResponse(final Response response) throws IOException
            {
                    //String htmlStr = response.body().string();}});Copy the code

This is still the simplest way to send a request, and the okHttpClient is not configured, which can cause code redundancy if okHTTP is used for network requests at multiple points in the project. Start the encapsulation:

  • First, encapsulate oneCommonRequestCreating a Request object
/** * Created by gechuanguang on 2017/2/17. * email: [email protected] * @functionReceive the Request parameters and generate the Request object */ for us
public class CommonRequest {
    / * * * @param url
     * @param params
     * @returnReturn a Request object */ with a post created
    public  static Request createPostRequest(String  url, RequestParams params){

        FormBody.Builder mFormBodybuilder = new FormBody.Builder();
        if(params! =null) {for(Map.Entry<String,String> entry: params.urlParams.entrySet()){
                // Add the request parameters to the request body one by one
                mFormBodybuilder.add(entry.getKey(),entry.getValue());
            }
        }
        FormBody mFormBody=mFormBodybuilder.build();
        return  new Request.Builder()
                .url(url)
                .post(mFormBody)
                .build();
    }

    / * * * @param url
     * @param params
     * @returnReturn a Request object */ with get created
    public  static Request createGetRequest(String  url, RequestParams params){

        StringBuilder urlBuilder=new StringBuilder(url).append("?");
        if(params! =null) {for(Map.Entry<String,String> entry: params.urlParams.entrySet()){
                // Add the request parameters to the request body one by one
                urlBuilder.append(entry.getKey()).append("=")
                        .append(entry.getValue())
                        .append("&"); }}return  new Request.Builder()
                .url(urlBuilder.substring(0,urlBuilder.length()-1)) // Remove the last ampersand
                .get()
                .build();
    }

    /** * File upload request ** @return* /
    private static final MediaType FILE_TYPE = MediaType.parse("application/octet-stream");

    public static Request createMultiPostRequest(String url, RequestParams params) {

        MultipartBody.Builder requestBody = new MultipartBody.Builder();
        requestBody.setType(MultipartBody.FORM);
        if(params ! =null) {
            for (Map.Entry<String, Object> entry : params.fileParams.entrySet()) {
                if (entry.getValue() instanceof File) {
                    requestBody.addPart(Headers.of("Content-Disposition"."form-data; name=\"" + entry.getKey() + "\" "),
                            RequestBody.create(FILE_TYPE, (File) entry.getValue()));
                } else if (entry.getValue() instanceof String) {

                    requestBody.addPart(Headers.of("Content-Disposition"."form-data; name=\"" + entry.getKey() + "\" "),
                            RequestBody.create(null, (String) entry.getValue())); }}}return newRequest.Builder() .url(url) .post(requestBody.build()) .build(); }}Copy the code

CommonRequest contains a Request object for post, a Request object for GET, and a Request object for file upload. You can then wrap the okhttpClient to send the request

  • encapsulationCommonOkhttpClient
/** * Created by gechuanguang on 2017/2/17. * email: [email protected] * @functionCreate an okHttpclient object and configure it to support HTTPS, and send requests */
public class CommonOkhttpClient {

    private static final int TIME_OUT = 30;
    private static OkHttpClient mOkHttpClient=null;

    // Start creating static code blocks once for mOkHttpClient to configure parameter class loads
    static {
        OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
        okHttpClientBuilder.connectTimeout(TIME_OUT, TimeUnit.SECONDS);
        okHttpClientBuilder.writeTimeout(TIME_OUT, TimeUnit.SECONDS);
        okHttpClientBuilder.readTimeout(TIME_OUT, TimeUnit.SECONDS);
        okHttpClientBuilder.followRedirects(true); // Setting redirection is true by default

        /*-- add the request header to your request --*/
// okHttpClientBuilder.addInterceptor(new Interceptor() {
// @Override
// public Response intercept(Chain chain) throws IOException {
// Request request = chain.request()
// .newBuilder()
AddHeader (" user-agent ", "Android -- Mobile") // Specifies the client that sent the request
// .build();
// return chain.proceed(request);
/ /}
/ /});

        // Add HTTPS support
        okHttpClientBuilder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String s, SSLSession sslSession) {
                return true; }});/** * trust all the https point */
        okHttpClientBuilder.sslSocketFactory(HttpsUtils.initSSLSocketFactory(),HttpsUtils.initTrustManager());
        mOkHttpClient = okHttpClientBuilder.build();
    }

    /** * Send a specific HTTP/HTTPS request * @param request
     * @param commonCallback
     * @return Call
     */
    public  static Call sendRequest(Request request, CommonJsonCallback commonCallback){
        Call call=mOkHttpClient.newCall(request);
        call.enqueue(commonCallback);
        return  call;
    }

    /** * Send a specific HTTP/HTTPS request * @param request
     * @param commonCallback
     * @return Call
     */
    public  static Call sendRequest(Request request, Callback commonCallback){
        Call call=mOkHttpClient.newCall(request);
        call.enqueue(commonCallback);
        returncall; }}Copy the code

OkHttpClient is configured to support HTTPS requests. If you are using Retrofit, you can configure okHttpClient to support HTTPS. Also note that INSTEAD of using the default CallBack CallBack, I’ve wrapped a layer of CommonJsonCallback, because the default CallBack is on the child thread, needs to switch to the main thread when updating the UI, and most of the time needs to convert Json strings into entity classes. Using the default Callback is very inconvenient. So I wrapped these operations into CommonJsonCallback to avoid repeating each time I switched threads and converted json to an entity class. It is worth thinking about why the okHTTP callback is called back to the child thread. For example, if we download a very large file, the response data to be called back must be very large and must be transferred to the SD card of the mobile phone in the form of stream. It needs to be transferred while downloading in the child thread to avoid memory overflow.)

  • CommonJsonCallbackSpecifically dealing with JSON callbacks
public class CommonJsonCallback implements Callback {

    /** * the logic layer exception, may alter in different app */
    protected final String RESULT_CODE = "ecode"; // A return is successful for the HTTP request, but it could also be a business logic error
    protected final int RESULT_CODE_VALUE = 0;
    protected final String ERROR_MSG = "emsg";
    protected final String EMPTY_MSG = "";
    protected final String COOKIE_STORE = "Set-Cookie"; // decide the server it
    // can has the value of
    // set-cookie2

    /** * 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 unknow error

    /** * forwards data from other threads to the UI thread */
    private Handler mDeliveryHandler;
    private DisposeDataListener mListener;
    privateClass<? > mClass;public CommonJsonCallback(DisposeDataHandle handle) {
        this.mListener = handle.mListener;
        this.mClass = handle.mClass;
        this.mDeliveryHandler = new Handler(Looper.getMainLooper());
    }

    @Override
    public void onFailure(final Call call, final IOException ioexception) {
        /** ** is still in a non-UI thread, so forward */
        mDeliveryHandler.post(new Runnable() {
            @Override
            public void run() {
                mListener.onFailure(newOkHttpException(NETWORK_ERROR, ioexception)); }}); }@Override
    public void onResponse(final Call call, final Response response) throws IOException {
        final String result = response.body().string();
        final ArrayList<String> cookieLists = handleCookie(response.headers());
        mDeliveryHandler.post(new Runnable() {
            @Override
            public void run() {
                handleResponse(result);
                /** * handle the cookie */
                if (mListener instanceofDisposeHandleCookieListener) { ((DisposeHandleCookieListener) mListener).onCookie(cookieLists); }}}); }private ArrayList<String> handleCookie(Headers headers) {
        ArrayList<String> tempList = new ArrayList<String>();
        for (int i = 0; i < headers.size(); i++) {
            if(headers.name(i).equalsIgnoreCase(COOKIE_STORE)) { tempList.add(headers.value(i)); }}return tempList;
    }
    private void handleResponse(Object responseObj) {
        if (responseObj == null || responseObj.toString().trim().equals("")) {
            mListener.onFailure(new OkHttpException(NETWORK_ERROR, EMPTY_MSG));
            return;
        }
        try {
            /** * how to modify */
// JSONObject result = new JSONObject(responseObj.toString());
            String result=responseObj.toString();
            if (mClass == null) {

                // Send the JSONObject type
// mListener.onSuccess(result);
                // Send a JSON string
                mListener.onSuccess(result);

            } else {
                /*-- convert json to entity class --*/
                Object obj = JsonUtils.fromJson(result.toString(), mClass);
                if(obj ! =null) {
                    mListener.onSuccess(obj);
                } else {
                    mListener.onFailure(newOkHttpException(JSON_ERROR, EMPTY_MSG)); }}}catch (Exception e) {
            mListener.onFailure(newOkHttpException(OTHER_ERROR, e.getMessage())); e.printStackTrace(); }}}Copy the code

The constructor for CommonJsonCallback is passed DisposeDataHandle,

  • DisposeDataHandle
public class DisposeDataHandle
{
    public DisposeDataListener mListener = null;
    publicClass<? > mClass =null;
    public String mSource = null;

    public DisposeDataHandle(DisposeDataListener listener)
    {
        this.mListener = listener;
    }

    public DisposeDataHandle(DisposeDataListener listener, Class<? > clazz) {this.mListener = listener;
        this.mClass = clazz;
    }

    public DisposeDataHandle(DisposeDataListener listener, String source)
    {
        this.mListener = listener;
        this.mSource = source; }}Copy the code

The DisposeDataHandle requires passing in a specific request callback, namely a DisposeDataListener

  • DisposeDataListener
public interface DisposeDataListener<T> {

    /** * Request successful callback event handling */
    public void onSuccess(T t);

    /** * Request failed callback event handling */
    public void onFailure(Object reasonObj);

}Copy the code

This concludes the encapsulation, and it’s time to see how to use it.

  • If you want to convert JSON to an entityclass object, you need to specify a generic for DisposeDataListener and pass databane.class at the end:
  CommonOkhttpClient.sendRequest(CommonRequest.createGetRequest(UrlConstant.wxUrl,null),
                        new CommonJsonCallback(new DisposeDataHandle(new DisposeDataListener<DataBean>() {
                            @Override
                            public void onSuccess(DataBean bean) {
                                mTextView.setText("onSuccess:"+bean.getAds().toString());
                            }
                            @Override
                            public void onFailure(Object reasonObj) {
                                mTextView.setText("onFailure:"+reasonObj.toString());
                            }
                        },DataBean.class)));Copy the code
  • If you want to return a JSON String directly, give the DisposeDataListener a generic String
  CommonOkhttpClient.sendRequest(CommonRequest.createGetRequest(UrlConstant.wxUrl,null),
                        new CommonJsonCallback(new DisposeDataHandle(new DisposeDataListener<String>() {
                            @Override
                            public void onSuccess(String json) {
                                mTextView.setText("onSuccess:"+json);
                            }
                            @Override
                            public void onFailure(Object reasonObj) {
                                mTextView.setText("onFailure:"+reasonObj.toString()); }})));Copy the code

The nice thing about this is that the code itself doesn’t reveal whether we’re using OKHTTP or another network framework, which means that if we need to switch to another network request framework, the application layer code doesn’t have to change.

This doesn’t seem good enough. In a specific project, I would create a RequestManager to manage these requests and actually send them in a line of code

/** * Created by gechuanguang on 2017/2/22. * email: [email protected] * @FunctionTo manage some network requests */
public class RequestManager {


    // Send all GET requests according to the parameters
    private static void getRequest(String url, RequestParams params, DisposeDataListener<? > listener, Class<? > clazz) { CommonOkhttpClient.sendRequest(CommonRequest.createGetRequest(url,params),new CommonJsonCallback(new DisposeDataHandle(listener,clazz)));
    }

    // Send all POST requests according to the parameters
    private static void postRequest(String url, RequestParams params, DisposeDataListener listener, Class<? > clazz) { CommonOkhttpClient.sendRequest(CommonRequest.createPostRequest(url,params),new CommonJsonCallback(new DisposeDataHandle(listener,clazz)));
    }

    /** * request home page data ** @param listener
     */
    public static void requestHomeData(Class clazz,DisposeDataListener<? > listener) { RequestManager.getRequest(UrlConstant.wxUrl,null,listener,clazz);
    }

    /** * Login * */
}Copy the code

The request can then be sent elsewhere as follows:

  RequestManager.requestHomeData(DataBean.class, new DisposeDataListener<DataBean>() {
                    @Override
                    public void onSuccess(DataBean bean) {
                        mTextView.setText(bean.getAds().toString());
                    }

                    @Override
                    public void onFailure(Object reasonObj) { mTextView.setText(reasonObj.toString()); }});Copy the code

This looks much cleaner and reduces the coupling between the code, at the application level only caring about whether the request login interface or the home interface, and whether the callback succeeds or fails.

The code addressGithubIf god has a better encapsulation idea, please let me know. I plan to maintain this Library and expand more things

Refer to the article

Blog.csdn.net/lmj62356579… Blog.csdn.net/lcq52113141…