### The evolution of Network requests in Android

Web programming is essential for Android development, and apps that are not connected to the Internet are not profitable. Without further ado, let’s look at the evolution of network requests on Android:

HttpURLConnection, Apache HTTP Client, Volley and now OKHttp. Why is OKHttp so popular? I believe the following introduction will tell you the answer.

A brief introduction to OKHttp

First of all, give OKHttp project address: https://github.com/square/okhttp

Android provides us with two HTTP interaction methods: HttpURLConnection and Apache HTTP Client, although both support HTTPS, stream upload and download, configured timeout, IPv6, and connection pooling, which are sufficient for our various HTTP requests. But using HTTP more efficiently can make your applications run faster and save traffic. The OkHttp library was born for this purpose. OkHttp is an efficient HTTP library that supports SPDY and shares the same Socket to handle all requests from the same server 2. If SPDY is not available, use connection pooling to reduce request latency 3. Seamlessly support GZIP to reduce data traffic 4. Cache response data to reduce repeated network requests

  • Generic GET requests
  • A normal POST request
  • Http-based file upload
  • File download
  • Loading pictures
  • Support request callback, directly return object, object collection
  • Session persistence is supported

OkHttp automatically recovers from many common connection problems. If your server is configured with multiple IP addresses, if the first IP address fails to connect, the next IP address will be automatically tried. OkHttp also handles proxy server issues and SSL handshake failures. Using OkHttp eliminates the need to rewrite the network code in your program. OkHttp realized almost as well as the java.net.HttpURLConnection API. If you use Apache HttpClient, OkHttp also provides a corresponding okHTTP-Apache module. As you can see from the above brief introduction, although it is not much simpler in terms of programming, OKHttp has some internal functions that can help us automate some very complicated operations. I personally think the biggest selling point of OKHttp is that it saves users a lot of traffic.

The basic use of OKHttp

1. Add CardView dependencies to Gradle.

The compile 'com. Squareup. Okhttp: okhttp: 2.7.2'Copy the code

Before using OKHttp, you should first understand the following core classes and their capabilities.

  • OkHttpClient Client object
  • Request is a Request accessed in OkHttp, and a RequestBody is required in a Post Request
  • Builder is the helper class for producing objects
  • Response is the Response in OkHttp, and in the Response, you can get whether it was successful or not, and return data
  • MediaType data type, used to indicate a range of formats such as JSON
  • RequestBody requests data, used in Post requests
  • Client.newcall (Request).execute() is a synchronous request method
  • Client.newcall (Request).enQueue (Callback Callback) is an asynchronous request method, but the code in Callback is executed on a child thread, so it cannot update the UI.

3. Basic steps to use OKHttp (taking JSON data from server via POST as an example)

  • To create the OkHttpClient object, the official documentation requires that we preferably use the singleton pattern, which will be discussed later when wrapping OKHttp.

  • For a POST request, create a RequestBody object using the FormEncodingBuilder to specify the parameters to post to. Get requests do not.

  • Create the Request object, which is the Request object and needs to specify the URL. A RequestBody object is required for POST requests, but not for GET requests.

  • Call OkHttpClient’s newCall method, pass in the Request object, and then execute or enQueue, as mentioned above. The onResponse method in CallBack does what you need to do. The onResponse callback takes response. In general, if we want to get the returned string, we can get response.body().string(); If you want an array of binary bytes returned, call response.body().bytes(); If you want to get the returned inputStream, you call Response.body ().bytestream () and you might be surprised to see that you can get the returned inputStream at all, but if you look at this, the least you can do is realize that it supports large file downloads, With inputStream we can write files by IO. But the onResponse thread is not the UI thread. Yes, if you want to manipulate controls, you still need to use handler, etc.

    OkHttpClient client = new OkHttpClient(); RequestBody body = new FormEncodingBuilder() .add("type", "1") .build(); Request request = new Request.Builder() .url(Constants.URL_BANNER) .post(body) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { } @Override public void onResponse(Response response) throws IOException { if (response.isSuccessful())  { android.os.Message msg = new Message(); msg.what = 1; msg.obj = response.body().string(); mHandler.sendMessage(msg); }}});Copy the code

This is just a simple POST request to get data from the server, and a GET request is nothing more than removing the RequestBody object. As for how to submit data to the server, consult the official WIKI (GitHub’s introduction documentation) once you are familiar with the basic usage above. Nan sister also recommend the article below, blog.csdn.net/lmj62356579… .

4. Simple encapsulation of OKHttp

Looking back at the code above, imagine if you were to write so much repetitive code for every request that it would be very inefficient to develop, so you would need to wrap OKHttp. Encapsulation of code is the basic quality of our object-oriented programmers, to reduce the duplication of code, reduce maintenance difficulty and cost.

OKHttp is also packaged on GitHub, called OKHttpUtils. But let’s do it ourselves and learn how to encapsulate it. Specific points to pay attention to are as follows:

First of all, OKHttp requires that we use the singleton mode to use the OKHttpClient class, so we will create a custom OKHttpHelper class and use the singleton mode.

2. To encapsulate get and POST methods, the main idea is to extract common code, such as the request method extracted from the code.

3. Expose some static methods, including get and POST methods.

Callback base class, which encapsulates the OKHttp Callback. This class has a type inside it, which is a wrapper to facilitate JSON parsing using Gson in callbacks. When using Callback, JSON can be easily used by passing in generics such as Data and List.

5. Since the original callback is not in the main thread, we need to use Handler to put the callback into the main thread.

The rest can refer to the code, with detailed comments.

import android.os.Handler; import android.os.Looper; import com.google.gson.Gson; import com.google.gson.JsonParseException; import com.squareup.okhttp.Callback; import com.squareup.okhttp.FormEncodingBuilder; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; import java.io.IOException; import java.util.Map; import java.util.concurrent.TimeUnit; /** * This class is used to assist OKHttp */ public class OkHttpHelper {/** * use OkHttpClient */ private static OkHttpHelper mOkHttpHelperInstance; private static OkHttpClient mClientInstance; private Handler mHandler; private Gson mGson; /** * private OkHttpHelper() {mClientInstance = new OkHttpClient(); mClientInstance.setConnectTimeout(10, TimeUnit.SECONDS); mClientInstance.setReadTimeout(10, TimeUnit.SECONDS); mClientInstance.setWriteTimeout(30, TimeUnit.SECONDS); mGson = new Gson(); mHandler = new Handler(Looper.getMainLooper()); } @return */ public static OkHttpHelper getInstance () {if (mOkHttpHelperInstance == null) {synchronized  (OkHttpHelper.class) { if (mOkHttpHelperInstance == null) { mOkHttpHelperInstance = new OkHttpHelper(); } } } return mOkHttpHelperInstance; } /** * encapsulates a request method, Public void request(final Request request, final BaseCallback callback) {public void request(final Request request, final BaseCallback callback) { Callback.onrequestbefore (); mClientInstance.newCall(request).enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) {// Return callbackFailure(request, callback, e); } @override public void onResponse(Response Response) throws IOException {if (response.issuccessful ()) {// Returns a successful callback String resString = response.body().string(); If (callback.mtype == string.class) {// If we need to return String callbackSuccess(response, resString, callback); } else {Gson = mgson.fromjson (resString, callback.mtype);} else {Gson = mgson.fromjson (resString, callback.mtype); callbackSuccess(response, o, callback); } catch (JsonParseException e) { e.printStackTrace(); callbackError(response, callback, e); }}} else {// return error callbackError(response, callback, null); }}}); } /** * Callback executed in the main thread ** @param response * @param resString * @param callback */ private void callbackSuccess(final) Response response, final Object o, final BaseCallback callback) { mHandler.post(new Runnable() { @Override public void run() { callback.onSuccess(response,  o); }}); } private void callbackError(final response response, final response, final response)  final BaseCallback callback, final Exception e) { mHandler.post(new Runnable() { @Override public void run() { callback.onError(response, response.code(), e); }}); } /** * @param request * @param callback * @param e */ private void callbackFailure(final Request request, final BaseCallback callback, final Exception e) { mHandler.post(new Runnable() { @Override public void run() { callback.onFailure(request, e); }}); } /** * public void get(String url) ** @param callback */ public void get(String url) BaseCallback callback) { Request request = buildRequest(url, null, HttpMethodType.GET); request(request, callback); } public void post(String url, Map<String, Map<String, Map<String); String> params, BaseCallback callback) { Request request = buildRequest(url, params, HttpMethodType.POST); request(request, callback); } /** * buildRequest object ** @param url * @param type * @return */ private Request buildRequest(String url, Map<String, String> params, HttpMethodType type) { Request.Builder builder = new Request.Builder(); builder.url(url); if (type == HttpMethodType.GET) { builder.get(); } else if (type == HttpMethodType.POST) { builder.post(buildRequestBody(params)); } return builder.build(); } /** * Private RequestBody buildRequestBody(Map<String, String> params) { FormEncodingBuilder builder = new FormEncodingBuilder(); if (params ! = null) { for (Map.Entry<String, String> entity : params.entrySet()) { builder.add(entity.getKey(), entity.getValue()); } } return builder.build(); } /** * this enumeration is used to specify the type of submission */ enum HttpMethodType {GET, POST}}Copy the code

Encapsulation of callbacks

package com.nan.cnshop.http; import com.google.gson.internal.$Gson$Types; import com.squareup.okhttp.Request; import com.squareup.okhttp.Response; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; Public class BaseCallback<T> {public class BaseCallback<T> {public class BaseCallback<T> { /** * convert type to the corresponding class. * * @param subclass * @return */ static Type getSuperclassTypeParameter(Class<? > subclass) { Type superclass = subclass.getGenericSuperclass(); if (superclass instanceof Class) { throw new RuntimeException("Missing type parameter."); } ParameterizedType parameterized = (ParameterizedType) superclass; return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]); } / * * * structure for the type of class * / public BaseCallback () {mType = getSuperclassTypeParameter (getClass ()); } public void onRequestBefore(); /** @param request * @param e */ public void onFailure(request request, Exception e); Public abstract void onSuccess(response response, t t); /** * if the request succeeds but there is an error, * * @param response * @param errorCode * @param e */ public abstract void onError(response response, int errorCode, Exception e); }Copy the code

5. Use OKHttp after encapsulation

This is shown in the code below. Get the singleton for OkHttpHelper first, and then call the GET method. Because you inherit from Gson, you need to pass in the JSON data type in the generic BaseCallback, which in my case is List. Finally, we just do what we want in the onSuccess method.

mHttpHelper=OkHttpHelper.getinstance();
mHttpHelper.get(Constants.URL_BANNER, new BaseCallback<List<Banner>>() {

    @Override
    public void onRequestBefore() {

    }

    @Override
    public void onFailure(Request request, Exception e) {

    }

    @Override
    public void onSuccess(Response response, List<Banner> banners) {
        initBanners(banners);
    }

    @Override
    public void onError(Response response, int errorCode, Exception e) {

    }
});
Copy the code

Do you think that using OKHttp is easy after encapsulation? That’s the power of encapsulation. That’s enough for today’s notes, see you tomorrow.

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

V. Attachments

BaseCallback.java

package com.nan.cnshop.http; import com.google.gson.internal.$Gson$Types; import com.squareup.okhttp.Request; import com.squareup.okhttp.Response; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; Public class BaseCallback<T> {public class BaseCallback<T> {public class BaseCallback<T> { /** * convert type to the corresponding class. * * @param subclass * @return */ static Type getSuperclassTypeParameter(Class<? > subclass) { Type superclass = subclass.getGenericSuperclass(); if (superclass instanceof Class) { throw new RuntimeException("Missing type parameter."); } ParameterizedType parameterized = (ParameterizedType) superclass; return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]); } / * * * structure for the type of class * / public BaseCallback () {mType = getSuperclassTypeParameter (getClass ()); } public void onRequestBefore(); /** @param request * @param e */ public void onFailure(request request, Exception e); Public abstract void onSuccess(response response, t t); /** * if the request succeeds but there is an error, * * @param response * @param errorCode * @param e */ public abstract void onError(response response, int errorCode, Exception e); }Copy the code

OkHttpHelper.java

package com.nan.cnshop.http; import android.os.Handler; import android.os.Looper; import com.google.gson.Gson; import com.google.gson.JsonParseException; import com.squareup.okhttp.Callback; import com.squareup.okhttp.FormEncodingBuilder; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; import java.io.IOException; import java.util.Map; import java.util.concurrent.TimeUnit; /** * This class is used to assist OKHttp */ public class OkHttpHelper {/** * use OkHttpClient */ private static OkHttpHelper mOkHttpHelperInstance; private static OkHttpClient mClientInstance; private Handler mHandler; private Gson mGson; /** * private OkHttpHelper() {mClientInstance = new OkHttpClient(); mClientInstance.setConnectTimeout(10, TimeUnit.SECONDS); mClientInstance.setReadTimeout(10, TimeUnit.SECONDS); mClientInstance.setWriteTimeout(30, TimeUnit.SECONDS); mGson = new Gson(); mHandler = new Handler(Looper.getMainLooper()); } @return */ public static OkHttpHelper getInstance () {if (mOkHttpHelperInstance == null) {synchronized  (OkHttpHelper.class) { if (mOkHttpHelperInstance == null) { mOkHttpHelperInstance = new OkHttpHelper(); } } } return mOkHttpHelperInstance; } /** * encapsulates a request method, Public void request(final Request request, final BaseCallback callback) {public void request(final Request request, final BaseCallback callback) { Callback.onrequestbefore (); mClientInstance.newCall(request).enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) {// Return callbackFailure(request, callback, e); } @override public void onResponse(Response Response) throws IOException {if (response.issuccessful ()) {// Returns a successful callback String resString = response.body().string(); If (callback.mtype == string.class) {// If we need to return String callbackSuccess(response, resString, callback); } else {Gson = mgson.fromjson (resString, callback.mtype);} else {Gson = mgson.fromjson (resString, callback.mtype); callbackSuccess(response, o, callback); } catch (JsonParseException e) { e.printStackTrace(); callbackError(response, callback, e); }}} else {// return error callbackError(response, callback, null); }}}); } /** * Callback executed in the main thread ** @param response * @param resString * @param callback */ private void callbackSuccess(final) Response response, final Object o, final BaseCallback callback) { mHandler.post(new Runnable() { @Override public void run() { callback.onSuccess(response,  o); }}); } private void callbackError(final response response, final response, final response)  final BaseCallback callback, final Exception e) { mHandler.post(new Runnable() { @Override public void run() { callback.onError(response, response.code(), e); }}); } /** * @param request * @param callback * @param e */ private void callbackFailure(final Request request, final BaseCallback callback, final Exception e) { mHandler.post(new Runnable() { @Override public void run() { callback.onFailure(request, e); }}); } /** * public void get(String url) ** @param callback */ public void get(String url) BaseCallback callback) { Request request = buildRequest(url, null, HttpMethodType.GET); request(request, callback); } public void post(String url, Map<String, Map<String, Map<String); String> params, BaseCallback callback) { Request request = buildRequest(url, params, HttpMethodType.POST); request(request, callback); } /** * buildRequest object ** @param url * @param type * @return */ private Request buildRequest(String url, Map<String, String> params, HttpMethodType type) { Request.Builder builder = new Request.Builder(); builder.url(url); if (type == HttpMethodType.GET) { builder.get(); } else if (type == HttpMethodType.POST) { builder.post(buildRequestBody(params)); } return builder.build(); } /** * Private RequestBody buildRequestBody(Map<String, String> params) { FormEncodingBuilder builder = new FormEncodingBuilder(); if (params ! = null) { for (Map.Entry<String, String> entity : params.entrySet()) { builder.add(entity.getKey(), entity.getValue()); } } return builder.build(); } /** * this enumeration is used to specify the type of submission */ enum HttpMethodType {GET, POST}}Copy the code

If you feel that my words are helpful to you, welcome to pay attention to my public number:

My group welcomes everyone to come in and discuss all kinds of technical and non-technical topics. If you are interested, please add my wechat huannan88 and I will take you into our group.