I still remember this time last year when I went to a new company to report. There were only about ten people in the company doing development. The guy who was working on Android just left and lost a project to me. In the days that followed, I suffered a lot. Today, we are going to give you an explanation on the part of accessing the network. Each time the interface data is obtained, it looks like this:

Where data are available:

In case of no data:

It is better to teach a man to fish than to give him fish.

####1

OKHttp: OKHttp: OKHttp: OKHttp: OKHttp: OKHttp: OKHttp

Call part

Map<String, Object> params = new HashMap<>(); // The specified parameter params.put("iid", 6152551759L);
        params.put("aid", 7);

        HttpUtils.get(this, ConstantValue.UrlConstant.HOME_DISCOVERY_URL,
                params, true, new HttpCallBack<DiscoverListResult>() {
                    @Override
                    public void onSuccess(DiscoverListResult result) {
                        if(result.isok ()) {// If there is no list data, print Toast or do something else}else{// If there is a list, display the list showListData(result); } } @Override public void onFailure(Exception e) { } });Copy the code

Encapsulation part

/** * get request data list * @param context * @param URL access path * @param params access parameters * @param cache cache * @param callback Public static <T> void get(Context Context, String URL, Map<String, Object> params, final boolean cache, final HttpCallBack<T> callback) { OkHttpClient mOkHttpClient = new OkHttpClient(); // Public parameter splice params.put("app_name"."joke_essay");
        params.put("version_name"."5.7.0");
        params.put("ac"."wifi");
        params.put("device_id"."30036118478");
        params.put("device_brand"."Xiaomi");
        params.put("update_version_code"."5701");
        params.put("manifest_version_code"."570");
        params.put("longitude"."113.000366");
        params.put("latitude"."28.171377");
        params.put("device_platform"."android"); final String jointUrl = Utils.jointParams(url, params); Request.builder requestBuilder = new Request.builder ().url(jointUrl).tag(context); Request Request = requestBuilder.build(); // MokHttpClient.newCall (request).enqueue(newCallback() {@override public void onFailure(Call Call, final IOException e) {// fail callback.onFailure(e); } @Override public void onResponse(Call call, Response response) throws IOException { final String resultJson = response.body().string(); // json conversion, no data list, cache processing}}); }Copy the code

This looks a little bit better, at least it can solve some problems, of course, some of the guys estimate that it is encapsulated by others that is a different matter, in fact, the year before the online packaging of OKHttp is relatively little, the key is not to think but very little.

####2. Chain call As the project gets bigger and bigger, the function becomes stronger and stronger, which obviously cannot meet the function, and more and more staff, ridicule follows, for example, cookie is not supported, HTTPS certificate, timeout disconnection reconnection and so on. The problem is that a method has to pass a lot of parameters, followed by a dozen parameters, and some parameters I do not want, can only pass null. First, member calls are very painful and need to be compared to your parameters one by one. Second, it is not nice and beautiful to read, so I made the following changes, and finally the call becomes the following:

Httputils.with (this).get() // get request.param ("aid", 7)// Add a single parameter. Params can add multiple parameters. Param ("iid", 6152551759 l). The url (ConstantValue. UrlConstant. HOME_DISCOVERY_URL) / / interface address setCookie (true)// Configure whether to use cookie. cache(true)// Set whether to use cache. If cache is used, set totrue.retrydelayMillis (1000)// Set the retry interval for failed requests, RetryCount (3)// Sets the number of retries for failed requests. Execute (new HttpCallBack<DiscoverListResult>() {@override public void onSuccess(DiscoverListResult result) {if(result.isok ()) {// If there is no list data, print Toast or do something else}else{// If there is a list, display the list showListData(result); } } @Override public void onFailure(Exception e) { } });Copy the code

####3. Single responsibility principle At this point, the technical director came up and asked, how can we put all the functions in one class, so that as the number of functions increases, HttpUtils classes will become larger and more complex code. HttpUtils has no design to speak of, let alone extensibility or flexibility. Network load encapsulation is increasingly fragile… Home to think along while, that I open a few more classes out of the line? That’s where the single responsibility comes in.

The English name of the Single Responsibility Principle is SRP. The definition is that there should be only one reason for a class to change. In simple terms, a class should be a collection of functions and data that are highly correlated. This is very clear in the book “Android source code design Pattern”, learn to use, what does it mean? See how I split it and post some sample code.

** * Email [email protected] * Created by Darren on 2017/3/12. * Version 1.0 * Description: Public String getCache(String finalUrl) {// Omit some code... } public long saveCache(String finalUrl, String resultJson) {// Omit some code... }}Copy the code
public class HttpUtils { private OKHttpRequest mHttpRequest; private HttpUtils(Context context) { mHttpRequest = new OKHttpRequest(); mHttpRequest.with(context); } // omit some code... }Copy the code

####3. Open and close principle after submitting the code, I felt that the idea was right, but later I thought that the fundamental problem was still not solved. At first, I wanted to change XUtils into OkHttp, but I never thought about changing every interface. I was wondering if I could make it stronger and switch without changing the original code. What should I do? Here comes the open close principle.

The Open Close Principle, or OCP for short, is the most fundamental design Principle in the Java world. It guides us how to build a stable and flexible system. The open closed principle is defined as: objects (classes, modules, functions, etc.) in software should be open for extension, but closed for modification. My understanding is that the original code is not modifiable inside, but is extensible externally. It’s still a little abstract, but if you combine it with my code, it’ll be better, but it’s just another interface.

/** * description: * author: Darren on 2017/8/21 11:36 * email: [email protected] * version: Private static IHttpRequest mInitHttpRequest; private static IHttpRequest mInitHttpRequest; private IHttpRequest mHttpRequest; public static void initHttpRequest(IHttpRequest httpRequest) { mInitHttpRequest = httpRequest; } // If there are two cases such as Volley downloading files is not so cool, HttpUtils httpRequest(IHttpRequest) {this.mhttprequest = httpRequest;returnthis; } // omit some code...... Public <T> void execute(HttpCallBack<T> callback) {// If this is not specified, then it is initialized in applicationif(mHttpRequest == null){ mHttpRequest = mInitHttpRequest; } mHttpRequest.get(mContext, mParams, mUrl, mCache, callback); }}Copy the code

IHttpRequest code

/** * description: * author: Darren on 2017/8/24 11:34 * email: [email protected] * version: 1.0 */ public interface IHttpRequest {/** * Post submit ** @param context * @param params * @param URL * @param cache * @param callback * @param <T> */ <T> void post(Context context, Map<String, Object> params, String url, final boolean cache, final HttpCallBack<T> callback); /** * get submit ** @param context * @param params * @param URL * @param cache * @param callback * @param <T> */ <T> void get(Context context, Map<String, Object> params, String url, final boolean cache, final HttpCallBack<T> callback); }Copy the code

OKHttpRequest code

/** * description: * author: Darren on 2017/8/24 10:32 * email: [email protected] * version: Public class implements IHttpRequest {private HttpCache mHttpCache; private OkHttpClient mOkHttpClient; publicOKHttpRequest() { mHttpCache = new HttpCache(); mOkHttpClient = new OkHttpClient(); } @Override public <T> void post(Context context, Map<String, Object> params, String url, boolean cache, HttpCallBack<T> callback) {// omit some code...... } public <T> void get(Context context, Map<String, Object> params, String url, final boolean cache, Final HttpCallBack<T> callback) {// Omit some code...... }}Copy the code

XUtilsRequest code

/** * description: * author: Darren on 2017/8/24 10:32 * email: [email protected] * version: Public class XUtilsRequest implements IHttpRequest {private HttpCache mHttpCache; publicXUtilsRequest() { mHttpCache = new HttpCache(); } @Override public <T> void post(Context context, Map<String, Object> params, String url, boolean cache, HttpCallBack<T> callback) {// omit some code...... } public <T> void get(Context context, Map<String, Object> params, String url, final boolean cache, Final HttpCallBack<T> callback) {// Omit some code...... }}Copy the code

The Application code

/** * description: * author: Darren on 2017/8/21 15:05 * email: [email protected] * version: Public class BaseApplication extends Application {@override public voidonCreate() { super.onCreate(); PreferencesUtil.getInstance().init(this); x.Ext.init(this); / / initialize the specified network request HttpUtils. InitHttpRequest (new XUtilsRequest ()); }}Copy the code

The open close principle instructs us that when software needs to change, it should be done by extension rather than by modifying existing code. We try not to add new implementations through inheritance or other means, which can lead to type bloat and redundant legacy code. Our development process is also not so ideal condition, completely without modifying the original code, therefore, in the development process of the need to combine the specific circumstances of consideration, is by changing the old code or through inheritance allows the software system is more stable, more flexible, at the same time of guarantee to remove corruption “code”, also ensure the correctness of the original module. Of course, if we understand the Builder design mode or add some other design mode after we can certainly write more powerful and perfect. Let’s keep going down.

####4. Richter’s Substitution principle

The Richter Substitution Principle is Liskov Substitution Principle, or LSP. As we know, the three characteristics of object-oriented language are inheritance, encapsulation and polymorphism, and Richter’s substitution principle relies on these two characteristics. The Richter substitution principle simply states that all references to a base class must be able to transparently use objects from its subclasses. In layman’s terms, subclasses can appear wherever a parent class can. However, the reverse is not true. Where there are subclasses, the parent class may not be able to adapt. Let’s briefly look at a few usage scenarios that are ubiquitous throughout our development process.

/ / 1. The initialization of the written request today HttpUtils. InitHttpRequest (new XUtilsRequest ()); HttpUtils.initHttpRequest(new OKHttpRequest()); / / 2. RecyclerView LayoutMananger mRecyclerView. SetLayoutManager (new LinearLayoutManager (this)); mRecyclerView.setLayoutManager(new GridLayoutManager(this,3)); // 3. Retrofit adds parsing factories, etcCopy the code

The use of the place is very much, setLayoutManager source we can go to understand, the above code is a good reaction to the Principle of Reeves replacement, XUtilsRequest, OKHttpRequest can replace the work of IHttpRequest. IHttpRequest established the post request, GET request, upload, download interface specification, XUtilsRequest according to the interface specification to achieve the corresponding functions, Users can dynamically replace requests in IHttpRequest by specifying specific objects in the Application. This makes network requests wireless, which ensures scalability.

Substitution principle and the open closed principle on the Richter scale is a little similar, but careful understanding between them are different concepts, can only say is sometimes open closed principle and magnitude of substitution principle often dependent life and death, who through the replacement on the Richter scale to achieve open for extension, but closed for modification, the effect of the two principles is object-oriented ideas in the abstract.

####5. Dependence Inversion Principle is Dependence Inversion Principle, abbreviated as DIP. The dependency inversion principle refers to a particular form of decoupling in which higher-level modules do not depend on the details of lower-level modules, which in other words do not depend on details but on abstractions. What is low level and what is high level? For example, HttpUtils is high level, IHttpRequest, XUtilsRequest, and OKHttpRequest are low level. HttpUtils started out like this:

public class HttpUtils { private OKHttpRequest mHttpRequest; private HttpUtils(Context context) { mHttpRequest = new OKHttpRequest(); mHttpRequest.with(context); } // omit some code... }Copy the code

In this case, we’re relying on a specific OKHttpRequest. In this case, we’re obviously relying on specific details. After the open and close principle, we’ll write HttpUtils like this.

/** * description: * author: Darren on 2017/8/21 11:36 * email: [email protected] * version: Private static IHttpRequest mInitHttpRequest; private static IHttpRequest mInitHttpRequest; private IHttpRequest mHttpRequest; public static void initHttpRequest(IHttpRequest httpRequest) { mInitHttpRequest = httpRequest; } // If there are two cases such as Volley downloading files is not so cool, HttpUtils httpRequest(IHttpRequest) {this.mhttprequest = httpRequest;returnthis; } // omit some code...... Public <T> void execute(HttpCallBack<T> callback) {// If this is not specified, then it is initialized in applicationif(mHttpRequest == null){ mHttpRequest = mInitHttpRequest; } mHttpRequest.get(mContext, mParams, mUrl, mCache, callback); }}Copy the code

At this time we rely on is no longer specific details, but abstract IHttpRequest, specific implementation we are configured in the Application, can configure Okhttp or xUtils, etc. From the above points, it seems that making the system more flexible has always been the work of abstraction.

####6. Interface Isolation Principle Interface isolation Principle is Full name of Interface isolation Principle (ISP). It is defined as: a client should not rely on interfaces it does not need. Another definition is that dependencies between classes should be established on the smallest interface. The interface isolation principle breaks down very large, bloated interfaces into smaller, more specific interfaces, so that customers will only need to know the methods they are interested in. The purpose of the interface isolation principle is to decouple systems so that they can be easily refactored, changed, and redeployed so that the interfaces on which clients depend are as small as possible.

Take a project I was working on recently as an example. I used my mobile phone to call the camera to take photos, but I didn’t have the source code. Later I thought of many ways to crack the camera, so the data I obtained needed to be timely transmitted to the background. I interrupt the Activity onDestory to open the Socket connection.

/** ** / private voidbreakConnection() {
        mReadFlag = false; // Close the input streamif(mInStream ! = null) { try { mInStream.close(); } catch (IOException e) { e.printStackTrace(); } // Close the output streamif(mOutStream ! = null) { try { mOutStream.close(); } catch (IOException e) { e.printStackTrace(); }} // Close the Socketif(mSocket ! = null) { try { mSocket.close(); mSocket = null; } catch (Exception e) { e.printStackTrace(); }}}Copy the code

This code is probably what we normally write, various try… Catch nesting, which is simple code, can seriously affect code readability, and multi-level braces can easily write code to the wrong level. You’re probably going to hate this kind of code, so let’s see how we can solve this problem. If we look at the source code, we see that they all have a close method that implements the Closeable interface, which identifies a Closeable object. This means that closing objects of a hundred or so types requires writing code like the one above, which makes no practical sense. That’s something! Since there are some commonalities, we can write another method:

/** ** / private voidbreakConnection() {
        mReadFlag = false; // Close (mInStream); // Close (mOutStream); Close (mSocket); } /** * Closeable * @param Closeable */ private void close(Closeable Closeable) {if(closeable ! = null) { try { closeable.close(); } catch (IOException e) { e.printStackTrace(); }}}Copy the code

The code is much simpler! This ensures code reuse. The basic principle of the close method is that it relies on the Closeable abstraction rather than the implementation, and is based on the principle of minimizing dependencies. It only needs to know that the object can be closed and does not care about anything else, namely the interface isolation principle.

Uncle Bob (Robert C Martin) defined the five principles of single responsibility, open closed principle, Ridley substitution, interface isolation and dependency inversion (also known as dependency inversion) as SOLID principles in the early 21st century, which refers to the five basic principles of object-oriented programming. When applied together, these principles make a software system clearer, simpler, and more open to change. SOLID is typically used in test-driven development and is an important part of the basic principles of agile development and adaptive software development. After this series of studies, we found that these principles can be reduced to the following key words: abstraction, single responsibility, and minimization. So how to balance and practice these principles in the actual development process, is that we need to think and understand more in practice, just as the so-called “learning without thinking is useless, thinking without learning is dangerous”, only continuous learning, practice, thinking, can have a qualitative leap in the process of accumulation.

####7. Least knowledge principle

The principle of least knowledge is also known as Law of Demeter, or LOD for short. Although it has a different name, it describes the same principle: one object should know the least about other objects. In layman’s terms, a class should know the least about the class it needs to couple or call. How the class’s internals are implemented and how complex they are doesn’t matter to the caller or dependent. The caller or dependent only needs to know the method he needs. The closer the relationship between classes, the greater the degree of coupling, when one class changes, the greater the impact on the other class.

Only talk to your immedate friends. What is an immediate friend? Every object is bound to have a coupling relationship with other objects, and the coupling between two objects becomes a friend relationship. There are many types of this relationship, such as composition, aggregation, dependency, and so on, which I won’t go into too much.

####8. At the end of the summary, I recommend a book “Android source code Design Pattern” to you, not to advertise, I did not take any benefits. A lot of people ask for the source code, but my code has always been private, and if it is, it is with other people’s code. What I really want to ask is is the code really that important? OKhttp comes with a cache, so I want to write my own cache, because there are different kinds of caches, for example, I want to cache it in memory, then cache it in data, then cache it in disk, or I just want to cache it in SharedPreferences so we can use this opportunity to practice, Of course, I won’t write any of this here, but based on some of the ideas above, I’m sure you have a way to write it well. Retrofit is not currently compatible, which we will have to wait to see the source code for Retrofit.

Finally, the most difficult part of the application development process is not to complete the application development work, but to make the application system embrace the change during the subsequent upgrade and maintenance process. Embracing change also means maintaining high scalability, high cohesion, low coupling, and a clear, flexible, and stable system architecture that meets requirements without disrupting system stability. Of course, this is an ideal situation, but we have to work towards it, and following the six principles of object orientation is the first step on the road to flexible software.

All shared outline: Android Advanced Journey – System Architecture chapter

Video on address: http://pan.baidu.com/s/1dFdABLZ