一篇使用Clean Architecture(整洁架构)模式开发Android的详细指南

该文章为翻译文章
文章出处: https://medium.com/@dmilicic/a-detailed-guide-on-developing-android-apps-using-the-clean-architecture-pattern-d38d71e94029

Ever since I started developing Android apps there was this feeling that it could be done better. I’ve seen a lot of bad software design decisions during my career, some of which were my own — and Android complexity mixed with bad software design is a recipe for disaster. But it is important to learn from your mistakes and keep improving. After a lot of searching for a better way to develop apps I encountered the Clean Architecture. After applying it to Android, with some refinement and inspiration from similar projects, I decided that this approach is practical enough and worth sharing.

自从我开始开发安卓后我就有一种它能变得更好的感觉。我曾经在我的职业生涯中遇到过很多糟糕的软件设计,有一些是我自己的项目--Android的复杂性与糟糕的软件设计的结合是导致灾难的诀窍。但是从中学习到自身的错误并且不断改善是非常重要的。在经过大量搜索寻找适合开发APP的方法后,我邂逅了Clean Architecture。在把它应用到安卓上后,通过相似项目的改进和灵感,我认为这种方法实用并且值得分享。

The goal of this article is to provide a step-by-step guide for developing Android apps in a Clean way. This whole approach is how I’ve recently been building my apps for clients with great success.

这篇文章的目的是通过提供一步步的指导来进行简洁的安卓项目开发。这整个方法建立在我最近开发客户端应用上取得巨大成功的基础上。

What is Clean Architecture?

什么是整洁架构

I will not go into too much detail here as there are articles that explain it much better than I can. But the next paragraph provides the crux of what you need to know to understand Clean.

我不会在这块深入太多的细节因为有太多相关的文章阐述的比我好。但是下一段是你需要理解整洁的关键点。

Generally in Clean, code is separated into layers in an onion shape with one dependency rule: The inner layers should not know anything about the outer layers. Meaning that the dependencies should point inwards.

通常的整洁,是指代码遵循一个准则分成类似洋葱装的层级:内部层级不需要知道外部层级的任何东西。这意味着依赖关系应该指向内部

This is the previous paragraph visualized:

这是先前段落的示意图
image.png

Clean Architecture, as mentioned in the provided articles, makes your code:
· Independent of Frameworks
· Testable.
· Independent of UI.
· Independent of Database.
· Independent of any external agency.

整洁架构,就像提及的文章所描述的一样,使你的代码:

· 独立架构
· 可测试
· 独立UI
· 独立数据库
· 独立于任何外部结构

I will hopefully make you understand how these points are achieved with examples below. For a more detailed explanation of Clean I really recommend this article and this video.

我非常希望你可以通过下面的例子来让你理解这些观点是如何实现的。更多关于整洁的细节阐述我真心推荐这篇文章和这个视频

What this means for Android

这对于安卓来说意味着什么

Generally, your app can have an arbitrary amount of layers but unless you have Enterprise wide business logic that you have to apply in every Android app, you will most often have 3 layers:
· Outer: Implementation layer
· Middle: Interface adapter layer
· Inner: Business logic layer

通常,你的app可以拥有任意数量的层级,但是除非你需要在你每个安卓App中实现企业级别的业务逻辑,大多数情况下你会分三个层级:

· 外层: 执行层
· 中层: 接口适配器层
· 内层: 业务逻辑层

The implementation layer is where everything framework specific happens. Framework specific code includes every line of code that is not solving the problem you set to solve, this includes all Android stuff like creating activities and fragments, sending intents, and other framework code like networking code and databases.

执行层是所有具体架构实现的地方。具体架构代码包括你设置解决但无法解决的每一行代码,这其中包括所有安卓内容如创建活动和片段、发送意图和其他的框架代码如网络代码和数据库。

The purpose of the interface adapter layer is to act as a connector between your business logic and framework specific code.

接口适配器层的目的就是扮演一个在你的业务逻辑和具体架构代码间的连接者。

The most important layer is the business logic layer. This is where you actually solve the problem you want to solve building your app. This layer does not contain any framework specific code and you should be able to run it without an emulator. This way you can have your business logic code that is easy to test, develop and maintain. That is the main benefit of the Clean Architecture.

最重要的层级是业务逻辑层。这是你实际解决构建应用程序时要解决的问题的地方。这一层级不包含任何具体框架的代码,并且你应该可以在不借助任何模拟器的情况下运行它。通过这种方式你可以得到易于测试、开发和维护的业务逻辑代码。这是Clean Architecture整洁架构的主要益处。

Each layer, above the core layer, is also responsible for converting models to lower layer models before the lower layer can use them. An inner layer can not have a reference to model class that belongs to the outer layer. However, the outer layer can use and reference models from the inner layer. Again, this is due to our dependency rule. It does create overhead but it is necessary for making sure code is decoupled between layers.

核心层上方的每个层级还负责在使用较低层时将模型转变成较低层模型。内层不能引用属于外层的模型类。但是,外层可以使用和引用内层的模型。同样,这是由于我们的依赖规则所制定的。它的确会产生开销但是必须确保代码在层级之间解耦。

Why is this model conversion necessary? For example, your business logic models might not be appropriate for showing them to the user directly. Perhaps you need to show a combination of multiple business logic models at once. Therefore, I suggest you create a ViewModel class that makes it easier for you to display it to the UI. Then, you use a converter class in the outer layer to convert your business models to the appropriate ViewModel.

为什么需要进行模型转换?例如,你的业务逻辑模型可能不适合直接展示给用户。或许你需要一次性展示多种业务逻辑模型的组合。所以,我建议你建立一个ViewModel类来使它更容易地用UI展示。然后,你在外层使用一个转换类来将你的业务模型转换为合适的ViewModel

Another example might be the following: Let’s say you get a Cursor object from a ContentProvider in an outer database layer. Then the outer layer would convert it to your inner business model first, and then send it to your business logic layer to be processed.

另一个可能的情况如下:假设你从外部数据库层级中的ContentProvider中获取Cursor对象。然后外层会首先将它转换为内层业务模型,之后将它发送到业务逻辑层进行处理。

I will add more resources to learn from at the bottom of the article. Now that we know about the basic principles of the Clean Architecture, let’s get our hands dirty with some actual code. I will show you how to build an example functionality using Clean in the next section.

我会在下面加入更多的资源以供参考。现在我们知道了一些Clean Architecture整洁架构的基本原理,让我们用实际的代码来让它更加清楚。我会在下一节中像你展示如何使用Clean构建示例功能。

How do I start writing Clean apps?

如何开始创建Clean项目?

I’ve made a boilerplate project that has all of the plumbing written for you. It acts as a Clean starter pack and is designed to be built upon immediately with most common tools included from the start. You are free to download it, modify it and build your apps with it.

我已经创建了一个样板项目 ,其中包含为你编写的所有管道。它作为一个Clean的启动包,旨在立即构建并包含最常用的工具。你可以自由下载、修改并使用它构建你的应用程序。

You can find the starter project here: Android Clean Boilerplate

你可以在这里找到[入门项目]

(https://github.com/dmilicic/Android-Clean-Boilerplate)

Getting started writing a new use case

开始编写新的用例

This section will explain all the code you need to write to create a use case using the Clean approach on top of the boilerplate provided in the previous section. A use case is just some isolated functionality of the app. A use case may (e.g. on user click) or may not be started by a user.

这一节将会阐述所有你需要写的代码来建立一个用例,以使用上一节中提供的样板文件顶部的Clean方法创建用例。一个用例就是一些应用程序独立的功能。一个用例(例如用户点击)可以或者不可以通过用户启动。

First let’s explain the structure and terminology of this approach. This is how I build apps but it is not set in stone and you can organize it differently if you want.

首先让我们解释这种方法的一些结构和术语。这就是我构建应用程序的方式,但它不是一成不变的,你可以用你的方式来组织它。

Structure

结构体

The general structure for an Android app looks like this:
· Outer layer packages: UI, Storage, Network, etc.
· Middle layer packages: Presenters, Converters
· Inner layer packages: Interactors, Models, Repositories, Executor

通常安卓应用程序的结构会像下面这样:

· 外层包: UI, Storage, Network等
· 中层包: Presenters, Converters
· 内层包: Interactors, Models, Repositories, Executor

Outer layer

外层

As already mentioned, this is where the framework details go.

就像已经提及过的那样,这是运行架构细节的地方。

UI — This is where you put all your Activities, Fragments, Adapters and other Android code related to the user interface.

UI-这是你放置你的Activities, Fragments, Adapters和其他安卓代码来和用户进行联系的地方

Storage — Database specific code that implements the interface our Interactors use for accessing data and storing data. This includes, for example, ContentProviders or ORM-s such as DBFlow.

Storage-实现Interactors用于访问数据库和存储数据接口的数据库特定代码。包括ContentProviders 或ORM-s,如 DBFlow

Network — Things like Retrofit go here.

NetWork-类似于Retrofit 运行的地方。

Middle layer

中层

Glue code layer which connects the implementation details with your business logic.

胶水代码层,用于将实现细节与业务逻辑相关联。

Presenters — Presenters handle events from the UI (e.g. user click) and usually serve as callbacks from inner layers (Interactors).

Presenters-Presenter来处理UI中的事件(如用户点击),通常用作内层的回调

Converters — Converter objects are responsible for converting inner models to outer models and vice versa.

Coverters-Converter对象负责把内部模型转换为外部模型,反过来也是这样。

Inner layer

内层

The core layer contains the most high-level code. All classes here are POJOs. Classes and objects in this layer have no knowledge that they are run in an Android app and can easily be ported to any machine running JVM.

核心层包含最高级的代码。这里所有的类都是POJO。这一层的类和对象不知道他们运行在安卓应用中并且可以轻松的移植到任何运行JVM的计算机上。

Interactors — These are the classes which actually contain your business logic code. These are run in the background and communicate events to the upper layer using callbacks. They are also called UseCases in some projects (probably a better name). It is normal to have a lot of small Interactor classes in your projects that solve specific problems. This conforms to the Single Responsibility Principleand in my opinion is easier on the brain.

Interactors-这些实际上是包含你业务逻辑代码的类。他们在后台运行并且通过回调函数向上层传递事件。特闷在某些项目中也称为UseCases(可能是更好的名称)。在项目组有很多小的Interactor类来解决特定的问题是很正常的。这符合单一责任原则,在我看来这是很容易理解的。

Models — These are your business models that you manipulate in your business logic.

模型-这些是你在业务逻辑中操作的业务模型。

Repositories — This package only contains interfaces that the database or some other outer layer implements. These interfaces are used by Interactors to access and store data. This is also called a repository pattern.

Repositories-这个包仅存储数据库或者外层实现的接口。Interactors使用这些接口来访问和存储数据。这也称作存储库模式

Executor**** — This package contains code for making Interactors run in the background by using a worker thread executor. This package is generally not something you need to change.

Executor-这个包包含使用线程执行程序使Interactors在后台运行的代码。这个包通常不是你需要改变的东西。

A simple example

一个简单的例子

In this example, our use case will be: “Greet the user with a message when the app starts where that message is stored in the database.” This example will showcase how to write the following three packages needed to make the use case work:
· the presentation package
· the storage package
· the domain package

在这个例子中,我们的用例将是:“当应用启动时,向用户询问消息存储在数据库中的位置。”这个示例将展示如何编写使用例工作所需要的三个包:

· 演示包
· 存储包
· 域包
The first two belong to the outer layer while the last one is the inner/core layer.

头两个属于外层包,最后一个是内层/核心包

Presentation package is responsible for everything related to showing things on the screen — it includes the whole MVP stack (it means it also includes both the UI and Presenter packages even though they belong to different layers).

Presentation包负责在屏幕上显示内容相关的所有内容-它包括整个MVP堆栈(这意味着它还包括UI包和Presenter包,即使他们属于不同的层)

推荐阅读更多精彩内容