A Brief History of Android Network Request Development and RxJava+Retrofit+OkHttp Practice

Keywords: network Retrofit OkHttp Android

Summary of Android Development Network Use

Summary

Android, as a smartphone platform with the same pace as IOS, has made great progress in nearly ten years, and the two platforms can PK out Nokia and the Symbian system that it used at that time, because of their rich functions based on the network. After several years of Android development, today I will summarize the network use of Android.

Android Network Request Recommendation Use and Development History

  • Before 2.2: HttpClient
  • After 2.3: HttpURLConnection
  • After the 2013 Google IO Conference: volley launched by Google's official team
  • After OkHttp: OkHttp
  • After Android 6.0, Google's official Api removed HttpClient (continued use of HttpClient and network libraries based on its encapsulation would cause exceptions)
  • Now: retrofit+OkHttp is recommended
  • The actual network layer used in my project is encapsulated as rxJava+retrofit+OkHttp, which briefly describes:
    • rxjava: responsible for subscription callbacks, cut request callbacks to the main thread, interception of intermediate callbacks, unified exception handling, etc.
    • Retrofit: Network Request Framework, with the use of OkHttp, makes network requests more convenient and powerful;
    • OkHttp: Similar to HttpClient and HttpURLConnection, the bottom layer actually handles Http requests.

1. The original way of network requests

1.1 HttpClient

Apache's library, which provides efficient, up-to-date and functional HTTP protocol toolkits, supports the latest version and recommendations of HTTP protocol, is a very good open source framework, encapsulates Http's requests, parameters, content bodies, responses and so on, and has many API s.
The most primitive way to request a network is powerful, but the API is complex. After 2.3, Google officially recommended using HttpURLConnection. Let's not expand here.

1.2 HttpURLConnection

Sun's library is also a member of Java's standard class library, java.net, but this class has nothing encapsulated and is very primitive to use. If advanced functions are needed, it will be inconvenient, such as re-access customization, session and cookie.
Before Android platform and Android version 2.2, HttpURLConnection was not perfect. There were some problems. The best way to request was HttpClient. After Android version 2.3, HttpURLConnection became the official recommended way of network request. Many open source network libraries were encapsulated by HttpURLConnection after version 2.3. For example, Google's official network framework Volley.

Specific differences between HttpClient and HttpURLConnection can be found in this article: The difference between HttpClient and HttpURLConnection (click to see)
HttpURLConnection request network code example:

/**
 * Tool class for Http requests based on HttpURLConnection
 *
 */
public class HttpUtils {

    private static final int TIMEOUT_IN_MILLIONS = 5000;

    public interface CallBack {
        void onRequestComplete(String result);
    }


    /**
     * Asynchronous Get Request
     *
     * @param urlStr
     * @param callBack
     */
    public static void doGetAsyn(final String urlStr, final CallBack callBack) {
        new Thread() {
            public void run() {
                try {
                    String result = doGet(urlStr);
                    if (callBack != null) {
                        callBack.onRequestComplete(result);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }

            ;
        }.start();
    }

    /**
     * Asynchronous Post Request
     *
     * @param urlStr
     * @param params
     * @param callBack
     * @throws Exception
     */
    public static void doPostAsyn(final String urlStr, final String params,
                                  final CallBack callBack) throws Exception {
        new Thread() {
            public void run() {
                try {
                    String result = doPost(urlStr, params);
                    if (callBack != null) {
                        callBack.onRequestComplete(result);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }

        }.start();

    }

    /**
     * Get Request, get the return data
     *
     * @param urlStr
     * @return
     * @throws Exception
     */
    public static String doGet(String urlStr) {
        URL url = null;
        HttpURLConnection conn = null;
        InputStream is = null;
        ByteArrayOutputStream baos = null;
        try {
            url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(TIMEOUT_IN_MILLIONS);
            conn.setConnectTimeout(TIMEOUT_IN_MILLIONS);
            conn.setRequestMethod("GET");
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            if (conn.getResponseCode() == 200) {
                is = conn.getInputStream();
                baos = new ByteArrayOutputStream();
                int len = -1;
                byte[] buf = new byte[128];

                while ((len = is.read(buf)) != -1) {
                    baos.write(buf, 0, len);
                }
                baos.flush();
                return baos.toString();
            } else {
                throw new RuntimeException(" responseCode is not 200 ... ");
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null)
                    is.close();
            } catch (IOException e) {
            }
            try {
                if (baos != null)
                    baos.close();
            } catch (IOException e) {
            }
            conn.disconnect();
        }

        return null;

    }

    /**
     * Send a request for a POST method to a specified URL
     *
     * @param url   The URL to send the request
     * @param param The request parameter should be in the form of name1 = value1 & Name2 = value2.
     * @return Response results of the remote resources represented
     * @throws Exception
     */
    public static String doPost(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // Open the connection between the URL
            HttpURLConnection conn = (HttpURLConnection) realUrl
                    .openConnection();
            // Setting Common Request Properties
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type",
                    "application/x-www-form-urlencoded");
            conn.setRequestProperty("charset", "utf-8");
            conn.setUseCaches(false);
            // To send a POST request, you must set the following two lines
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setReadTimeout(TIMEOUT_IN_MILLIONS);
            conn.setConnectTimeout(TIMEOUT_IN_MILLIONS);

            if (param != null && !param.trim().equals("")) {
                // Get the output stream corresponding to the URLConnection object
                out = new PrintWriter(conn.getOutputStream());
                // Send request parameters
                out.print(param);
                // Buffer of flush output stream
                out.flush();
            }
            // Define the BufferedReader input stream to read the response of the URL
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // Close the output and input streams using the final block
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }
}

2 Advanced Model of Network Request

2.1 Volley

Google's official web access framework, launched at the 2013 Google IO conference, is no longer recommended. For more information, please refer to this article: Volley Source Parsing

2.2 Other Encapsulated Network Request Framework

The third-party encapsulated network request frameworks like volley include Final Http, android-async-http and so on. They are basically based on HttpClient and HttpURLConnection encapsulation. They are not very different in essence. The convenience and flexibility of each library encapsulation are different.

3 Fashion Mode of Network Request (RxJava+Retrofit+OkHttp Practice)

3.1 OkHttp

OkHttp is an excellent HTTP framework. It supports get and post requests, Http-based file upload and download, loading pictures, transparent GZIP compression of downloaded files, response cache to avoid duplicate network requests, and connection pool to reduce response latency.
For the introduction and integration of OkHttp, please refer to this official tutorial: Analysis of OkHttp Official Tutorial - A thorough introduction to OkHttp usage

3.2 OkHttp Combined with Retrofit

Most of the projects using OkHttp will cooperate with Retrofit, which is the same as Retrofit. The combination of the two is more powerful.
And the network framework I used in the actual development is the combination of rxJava+Retrofit+OkHttp.
No nonsense, go directly to the code:

Let's start with the call example:
Step 1: Add an interface to ApiService
* 1. Write the method name rxGetTest of the request network and the Bean object WeatherInfo deserialized by Json of the return parameter of the interface.
* 2. Configure the suffix of Url on the @GET parameter, such as @GET("data/sk/101091001.html");
The url of the actual request is http://www.weather.com.cn/data/sk/101091001.html
The BaseUrl configured in retrofit is http://www.weather.com.cn/ So just write the suffix to remove Baseurl here.

package com.bailiangjin.httprequest.rxokdemo;

import com.bailiangjin.httprequest.net.rxretrofitokhttp.design.BaseData;
import com.bailiangjin.httprequest.rxokdemo.model.PostInfo;
import com.bailiangjin.httprequest.rxokdemo.model.WeatherInfo;

import java.util.Map;

import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import rx.Observable;

/**
 * The network request Service method summary binds the invoked method here to rx
 * Created by bailiangjin on 2017/2/15.
 */
public interface ApiService {

    @GET("data/sk/101091001.html")
    Observable<WeatherInfo> rxGetTest();

    @GET("query?type=yuantong&postid=200382770316")
    Observable<PostInfo> rxGetPostInfo();


    /**
     * Post FormUrlEncoded identifier needs to be added to the mode request
     * @param map
     * @return
     */
    @FormUrlEncoded
    @POST("/")
    Observable<BaseData<PostInfo>> rxPostTest(@FieldMap Map<String, String> map);

}

The second part of the request network code is as follows, is not it very cool: ___________
"`
// Example RxRequestHelper. requestNotDealCommonError (get WeatherApiService (). rxGetTest (), new CommonResponseSubscriber (){
@Override
public void onNext(WeatherInfo weatherInfoBaseData) {
// Specific Processing of Getting Callback Data
}
});

// Example of post invocation
/**
* The post example does not use public exception handling, but only writes about how to use specific tests. Please use your own interface tests.
* @param subscriber
*/
Map

The getWeatherApiService() used in the above code is actually an ApiService object, which is generated by the following code. If BaseUrl uses only one ApiService consistently, it can be written once, and then only two parts are added at a time. If BaseUrl requests more than one interface, it doesn't matter. A new BaseUrl's Rue can be added by adding one line of code. Trofit, is it very powerful, in fact, this is mainly through enumeration, you can see the code in the project in detail, not discussed here.

package com.bailiangjin.httprequest.rxokdemo;

import com.bailiangjin.httprequest.net.rxretrofitokhttp.tools.RetrofitCollection;

import retrofit2.Retrofit;

/**
* Weather Service
* Created by bailiangjin on 2017/2/16.
*/

public enum WeatherApiService {
INSTANCE;
private ApiService apiService;
private Retrofit retrofit;

WeatherApiService() {
    retrofit = RetrofitCollection.WEATHER_INSTANCE.getRetrofit();
    apiService = retrofit.create(ApiService.class);
}

public ApiService getApiService() {
    return apiService;
}

public String getBaseUrl() {
    return retrofit.baseUrl().toString();
}

}

The other core codes are as follows:

package com.bailiangjin.httprequest.net.rxretrofitokhttp.tools;

import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;

/**
*
* Bottom-level OKHttpClient
* Created by bailiangjin on 2017/2/16.
*/

public enum MyOkHttpClient {

INSTANCE;

private OkHttpClient okHttpClient;

MyOkHttpClient() {
    okHttpClient = new OkHttpClient.Builder()
            //. cache(cache) // disable okhttp's own cache
            .connectTimeout(10, TimeUnit.SECONDS)
            .readTimeout(10, TimeUnit.SECONDS)
            .writeTimeout(10, TimeUnit.SECONDS)
            .retryOnConnectionFailure(true)
            .addInterceptor(new MyInterceptor())
            .addInterceptor(new HttpLoggingInterceptor())
            .build();
}

public OkHttpClient getOkHttpClient() {
    return okHttpClient;
}

static class MyInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request.Builder builder = chain.request().newBuilder();
        //Add header
        //CommonNetUtils.addHeader(builder);
        //Modify the request to read data only from the network
        Request request = builder
                .cacheControl(CacheControl.FORCE_NETWORK).build();
        return chain.proceed(request);
    }
}

}



package com.bailiangjin.httprequest.net.rxretrofitokhttp.tools;

import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
* Retrofit Collections can easily add retrofit for different root URLs by adding enumerated elements
* @author bailiangjin 2017-02-16
*/
public enum RetrofitCollection {
WEATHER_INSTANCE("http://www.weather.com.cn/"),
EXPRESS_INSTANCE("http://www.kuaidi100.com/");
private Retrofit retrofit;

RetrofitCollection(String baseUrl) {
    retrofit = new Retrofit.Builder()
            .client(MyOkHttpClient.INSTANCE.getOkHttpClient())
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            //You can also add custom RxJavaCallAdapterFactory
            .build();
}

public Retrofit getRetrofit() {
    return retrofit;
}

}

package com.bailiangjin.httprequest.net.rxretrofitokhttp.tools;

import com.bailiangjin.httprequest.net.rxretrofitokhttp.design.BaseData;
import com.bailiangjin.httprequest.net.rxretrofitokhttp.design.CommonErrors;

import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/**
* RexHelper Class Function 1 of Network Request, Binding Callback of Network Request to Main Thread 2, Unified exception handling can be selected according to need.
* Created by bailiangjin on 2017/2/16.
*/

public class RxRequestHelper {

/**
 * Binding callback to mainthread and handling exceptions uniformly
 * @param observable
 * @param subscriber
 * @param <T>
 * @return
 */
public static <T> Observable requestDealCommonError(Observable<BaseData<T>> observable, Subscriber<BaseData<T>> subscriber) {
    mapCommonErrors(observable);
    setSubscribeToAndroidMainThread(observable, subscriber);
    return observable;
}



/**
 * Binding callbacks to mainthread do not handle exceptions uniformly
 * @param observable
 * @param subscriber
 * @param <T>
 */
public static <T> void requestNotDealCommonError(Observable<T> observable, Subscriber<T> subscriber) {

    setSubscribeToAndroidMainThread(observable, subscriber);
}


/**
 * Switch callback to MainThread
 * @param observable
 * @param subscriber
 * @param <T>
 */
private static <T> void setSubscribeToAndroidMainThread(Observable<T> observable, Subscriber<T> subscriber) {
    observable.subscribeOn(Schedulers.io())
            .unsubscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(subscriber);
}

/**
 * Unified exception handling
 * @param observable
 * @param <T>
 */
private static <T> void mapCommonErrors(Observable<BaseData<T>> observable) {
    observable.map(new CommonErrors<T>());
}

}

"`

For space, only part of the code is posted in the article. For practical experience, please clone my GitHub project code to run specifically: Github network request code link: AndroidHttpRequest (Click to see)

3.3 Other open source libraries based on OkHttp

In fact, OkHttp is not a network framework. Its attributes and functions are similar to HttpClient and HttpURLConnection. They are the specific ways of Http requesting network. When OkHttp is widely used, there will be many more convenient third-party frameworks based on OkHttp encapsulation, which are not developed here. If you are interested in it, you can go to Google.

All the code in this article can be accessed to my github project AndroidHttpRequest Check in.

More excellent articles recommend:
Android Activity Global Management Ultimate Solution
Minimalist Encapsulation of Android BaseAdapter

Posted by gerrydewar on Sat, 06 Apr 2019 09:09:32 -0700