Updates about Clean Architecture in Android

1. Introduction to clean Architecture

The Clean architecture is the brainchild of Uncle Bob, who recently released five. Agency /blog/ Androi… Several articles on the Clean architecture have been read to deepen your understanding of the architecture.

The Clean architecture is also known as the Onion Architecture, which is named for its architecture diagram

Delete some things that are not used in the Android project and add the ones we used to look like the following

2. Core concepts

From the most abstract core to the edge of detail

Entities

Entities, Domain objects or business objects, are at the heart of your App. They represent the main functions of the APP, they contain business logic, and they don’t interact with the details of the outside world.

Use cases

Use Case, also known as Interactors, also known as Business Services, is an extension of Entities, an extension of business logic, that is. They contain logic that is not limited to one entity, but deals with many more entities.

Repositories

Repositories for Persistent Entities. It’s that simple. They are defined as interfaces and serve as output ports for use cases that want to perform CRUD operations on Entities.

Presenters

If you are familiar with the MVP model, Presenters will do what you expect them to do. They handle user interactions, invoke the appropriate business logic, and send data to the UI for rendering. There are usually mappings between different types

These concepts may help us understand the Clean architecture better, but the core point is that the more abstract it gets inside the onion.

3. Core rules of the Clean architecture

The first thing to do is to Master the domain, which is called “Master of your domain,” which means that when you open up your project, apart from the technical aspects, you should know what your app does at a macro level, and not get bogged down in the details. “Why do we need to look at our project at this level, Because that’s where the core of Clean is, the architecture gets more and more abstract as it gets deeper and deeper into the onion, the high abstraction of the business logic, “the inner layer contains the business logic, the outer layer contains the implementation details.”

The technical points needed to design a Clean architecture with such features are presented

(1) Dependency rule

(2) Abstraction

(3) Communication between layers

Here are some of them

3.1 Dependency Rule

From the very first picture we can see that the arrow is “dependent “, that is, the outer layer sees and knows the inner layer, but the inner layer neither sees nor knows the outer layer. In combination with the previous emphasis that the inner layer contains the business logic (abstraction) and the outer layer contains the implementation details. Combined with dependency rules, the business logic neither sees nor knows the implementation details. Often we can adjust their dependencies by placing them in different modules

3.2 Abstraction

And I said before that as you move toward the middle of the diagram, things get more abstract. This makes sense: abstractions are often more stable than details, like building blocks.

For example, we can define the abstract interface as “load network image” and put it in the inner layer so that the business logic can use it to display the image. On the other hand, we can call a specific image loading library glide or Picasso by implementing the interface, and then put the implementation in the outer layer. The business logic can use the load picture feature without knowing anything about the implementation details. This protects against the risk that the abstract business logic inside the onion will not know how to load images in the future

Communication between layers

Now that you’ve divided the layers, separated the content, and placed the business logic in the architectural center and implementation details at the architectural edges of the application, everything looks great. But you may soon run into an interesting problem.

If your UI is an implementation detail, then the Internet is an implementation detail, and the business logic is somewhere in between, how do we get data from the Internet, pass it through the business logic, and then send it to the screen?

Combination and inheritance come into play

4, practice

Using RSS Reader as an example, our users should be able to manage their RSS feed subscriptions, get articles from the feed, and read them.

Here is the data flow problem, where use cases fall between the presentation layer and the data layer. How do we establish communication between layers? Remember the input and output ports?

As you can see from the figure above, our Use Case must implement an input port (interface). Presenter invokes methods on the Use Case, and data flows to the Use Case (feedId). Use Case map feedId provides articles and wants to send them back to the presentation layer. It has a reference to the output port (callback), and because the output port is defined in the same layer, it calls a method. Therefore, data is sent to the output port – Presenter.

Let’s start with the Domain layer to create our core business model and logic.

Our business model is very simple:

  • Feed – Holds RSS Feed related data such as url, thumbnail URL, title and description
  • Article – Saves data related to the Article, such as the Article title, url, and publication date

For our logic, we’re going to use UseCases. They encapsulate small pieces of business logic in compact classes. They will all implement the common UseCase contract interface:

public interface UseCase<P, R> {

 interface Callback<R> {
 void onSuccess(R return);
 void onError(Throwable throwable);
 }

 void execute(P parameter, Callback<R> callback);
}



public interface CompletableUseCase<P> {

 interface Callback {
 void onSuccess();
 void onError(Throwable throwable);
 }

 void execute(P parameter, Callback callback);
}
Copy the code

The UseCase interface is the input port, the Callback interface is the output port, and the GetFeedArticlesUseCase implementation is as follows

class GetFeedArticlesUseCase implements UseCase<Integer, List<Article>> { private final FeedRepository feedRepository; @Override public void execute(final Integer feedId, final Callback<List<Article>> callback) { try { callback.onSuccess(feedRepository.getFeedArticles(feedId)); } catch (final Throwable throwable) { callback.onError(throwable); }}}Copy the code

And then the UI implementation outside of the onion, View has a simple contract class

interface View {

 void showArticles(List<ArticleViewModel> feedArticles);
 
 void showErrorMessage();
 
 void showLoadingIndicator();
}
Copy the code

The Presenter of this view has very simple display logic. It takes articles, maps them to the View odels and passes them to the View, and look at FeedArticlesPresenter:

class FeedArticlesPresenter implements UseCase.Callback<List<Article>> { private final GetFeedArticlesUseCase getFeedArticlesUseCase; private final ViewModeMapper viewModelMapper; public void fetchFeedItems(final int feedId) { getFeedArticlesUseCase.execute(feedId, this); } @Override public void onSuccess(final List<Article> articles) { getView().showArticles(viewModelMapper.mapArticlesToViewModels(articles)); } @Override public void onError(final Throwable throwable) { getView().showErrorMessage(); }}Copy the code

Here you can see that FeedArticlesPresenter implements the Callback interface and passes itself to Use Case, which is in effect the output port of Use Case and shuts down the data flow in this way

Google’s Architecture project also has a todo-MVP-Clean branch to see how it works.

5, summary

This is closely related to dependency inversion and interface isolation in design patterns. By dependency inversion, relying only on abstractions rather than details, the implementation of details is inverted into implementation classes, so that the core of the Onion is clean business logic (abstraction).

In general, a good architecture needs to meet the following requirements:

  1. (2) Satisfy all stakeholders.
  2. Encourage separation of concerns.
  3. Run away from the real world (Android, DB, Internet…) .is a high level of abstraction
  4. Enable your components to be testable.

However, an architecture is often targeted at a specific scenario, and the architecture also needs to evolve slowly. For example, the later modularization and plug-in are all aspects of the business development to a certain extent, and the drawbacks of the current architecture are gradually highlighted and need to be updated. But no matter how it changes, some of the core fundamentals remain — dependency flipping, interface oriented programming, separation of concerns — are just some of the skills we need to shine on.

reference

1, five. Agency/blog/androi…

2, five. Agency/android – arc…

3, five. Agency/android – arc…

Welcome to pay attention to my public number, learn together, improve together ~