Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the most practical Android architecture design principle?

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

What is the most practical principle of Android architecture design? I believe many inexperienced people don't know what to do about it. Therefore, this paper summarizes the causes and solutions of the problem. Through this article, I hope you can solve this problem.

Before you begin, suppose you have read my previous article "Architecting Android … The clean way?". If you have not read it, in order to better understand this article, you should take this opportunity to read:

Architecture evolution

Evolution means a gradual process, changing from one state to another, and the new state is usually better or more complex.

In this way, software develops and changes over time, and it is an architectural development and change. In fact, good software design must help us develop and expand the solution and keep it robust without having to rewrite everything (although rewriting is better in some cases, that's the topic of another article, so believe me, let's focus on the topic discussed earlier).

In this article, I will explain what I think is necessary and important. In order to keep the basic code organized, to remember the following picture, let's get started!

Responsive approach: RxJava

I'm not going to discuss the benefits of RxJava here (I assume you've already experienced it) because there are a lot of articles about it and people who do a good job of it. However, I will point out the interesting aspects of Android application development and ways to help me form a clear architecture.

First, I chose a responsive pattern to return Observables by transforming usecase (in this clear schema naming convention, which is called interactor), indicating that all the underlying layers follow this chain and also return Observables.

As you can see, all use cases inherit this abstract class and implement the abstract method buildUseCaseObservable (). This method creates an Observables that takes on a lot of work and returns the required data.

It is important to emphasize that in the execute () method, you want to ensure that the Observables is executed in a separate thread, so block the android main thread as little as possible. The result is that the main thread is pushed into the end of the thread queue (push back) through the android main thread scheduler.

So far, our Observables is up and running. But, as you know, you have to look at the sequence of data it sends out. To do this, I improved presenters (part of the MVP schema presentation layer) to turn it into a Subscribers, which makes "react" of emitted projects through use cases to update the user interface.

The observer goes like this:

Each observer is the inner class of each presenter and implements a Defaultsubscriber interface that creates basic default error handling.

After putting all the pieces together, you can get the complete concept through the following figure:

Let's list some of the benefits of getting rid of the RxJava-based approach:

Decoupling between the Subscribers and the Observables: easier to maintain and test.

Simplify asynchronous tasks: if more than one level of asynchronous execution is required, the operation and synchronization of Java's thread and future are more complex, so by using the scheduler, we can easily jump between the background and the main thread (without extra work), especially when we need to update UI. We can also avoid a "callback pit"-it makes our code less readable and difficult to follow.

Data conversion / composition: without affecting the client, we can integrate multiple Observables to make the solution more flexible.

Error handling: when an error occurs within any Observables, it signals to the consumer.

From my point of view, it's a little inadequate, and there's even a price to pay for it, and developers who are not yet familiar with the concept still have to follow the learning curve. But you get something of great value from it. Reactive for success. Get up!

Dependency injection: Dagger 2

I don't want to say too much about dependency injection because I've written a complete article. It is strongly recommended that you read it so that we can move on to the following.

It is worth mentioning that by implementing a dependency injection framework like Dagger 2, we can obtain:

Components are reused because dependent objects can be injected and configured externally.

When injecting an object as a collaborators, because the instance of the object exists in a place of isolation and decoupling, we can change the implementation of any object without much change in our code base.

Dependencies can be injected into a component: these make it possible to inject dependent objects for these mock implementations, which makes testing easier.

Lambda expression: Retrolambda

No one complains about using Java 8 lambada expressions in your code, even after simplifying and getting rid of a lot of boilerplate code, as you can see:

However, I have mixed feelings. Why? We discussed Retrolambada at @ SoundCloud, mainly whether to use it or not, and the result is:

1. Reasons for approval:

Lambda expressions and method references

"try-with-resources" statement

Use karma for development

two。 Reasons for objection:

Unexpected use of Java 8 API

A very objectionable third-party library

Third-party plug-in Gradle to be used with Android

*, we decided that it wouldn't solve any problems for us: your code looks good and readable, but that's not what we coexist with, since all functional IDE now contain code folding options, which covers this requirement, at least in an acceptable way.

To be honest, although I might use it in my spare time projects, the main reason for using it here is to try and experience Lambda expressions in Android. It's up to you to decide whether to use it. I'm just showing my vision here. Of course, the author of this library deserves my praise for such a great work.

Testing method

In terms of testing, the parts related to the * versions of the example have not changed much:

Presentation layer: test UI with Espresso 2 and Android Instrumentation test framework.

Domain layer: JUnit + Mockito-this is the standard module of Java.

Data layer: replace the test combination with Robolectric 3 + JUnit + Mockito. Testing at this layer once existed in a separate Android module. Since there was no support for built-in unit tests and no framework like robolectric was built at that time (the current version of the sample program), the framework was complex and needed the help of a group of hackers to make it work.

Fortunately, this is all part of the past, and now everything is available immediately, so I can put them back into the data module specifically for its default test path: src/test/java.

Organization of the package

I think one of the key elements of a good architecture is the organization of code / packages: the only thing programmers encounter when browsing the source code is the package structure. Everything flows out of it, everything depends on it.

We can identify two paths to encapsulate the application into a package:

Subcontracting by layer: the items contained in each package are not usually closely related to each other. In this way, the cohesion of packets is low, the degree of modularization is low, and the degree of coupling between packets is high. Therefore, editing a property involves editing files from different packages. In addition, it is almost impossible to delete a feature in a single operation.

Subcontract by feature: use package to reflect the feature set. Put all items related to a feature (and only the feature) into a package. In this way, the package has high cohesion, high degree of modularization and low coupling between packets. Closely related items are put together. They are not scattered throughout the application.

My suggestion is to remove the subcontracting by feature, which will bring the following main benefits:

Higher degree of modularization

Code navigation is easier

The scope of functional features is minimized

It can also be fun to work with the feature team (as we did at @ SoundCloud). Ownership of the code is easier to organize and easier to modularize. This is a success in a growing organization where many developers share a code base.

As you can see, my approach looks like subcontracting by layer: here I may make mistakes (for example, organizing everything under "users"), but in this case I forgive myself because this is a learning example, and I want to show the main concepts of a clear architectural approach. Understand the meaning, do not imitate blindly: -).

What needs to be done: organizational building logic

As we all know, the house is built on the foundation. The same is true of software development, and what I want to say is that, from my point of view, building systems (and their organizations) is an important part of software architecture.

On the Android platform, we use Gradle, which is actually a platform-independent build system with very powerful functions. The idea here is to simplify your organization when building applications through some tips and techniques.

Group content by function in a separate gradle build file

Therefore, you can use "apply from: 'buildsystem/ci.gradle'" to insert into any file created by Gradle for configuration. Don't put it all in one build.gradle file, or you will create a monster. This is the lesson.

Create a dependency graph

It's good if you want to reuse the same component version between different modules of the project; otherwise you will have to use different versions of component dependencies between different modules. On the other hand, you control dependencies in the same place, and you can tell at a glance that there are conflicts between component versions.

Conclusion

I want to point out something. In the face of the problems existing in the software, we should adopt the attitude that should be solved:

Abide by the SOLID principle

Don't think too much (not over-engineered)

Be pragmatic

Minimize the dependency of modules in the (Android) framework

After reading the above, have you mastered what are the most practical Android architecture design principles? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report