当我开始作为一名 Android 开发者的旅程时,“移动应用架构”这个词让我深感困惑,Google 和 Habré 上的文章让我陷入了更大的沮丧——我看着书,什么也没看到。我想如果你正在阅读这篇文章,你已经不止一次地研究过这张图,并试图理解正在发生的事情: 在我看来,理解移动开发中的架构方法的问题在于架构本身的抽象性。每个开发人员对于如何正确实现这个或那个模式都有自己的愿景。在互联网的英语领域中或多或少都可以找到 MVP 实施的不错例子,这并不奇怪。让我们简要了解一下什么是什么,然后继续看一个示例。 模型-数据级别。我不喜欢使用“业务逻辑”这个术语,所以在我的应用程序中我将其称为存储库,它与数据库和网络进行通信。 视图——显示级别。如果你不喜欢手鼓跳舞以及与生命周期交互,那么它将是Activity、Fragment或Custom View 。让我提醒您,最初所有 Android 应用程序都从属于MVC结构,其中控制器是Activity或Fragment。 Presenter是View和Model之间的一层。View 传输发生在它身上的事件,presenter 处理它们,如有必要,访问 Model 并将数据返回给 View 进行渲染。关于Android和一个具体的例子,我将重点强调重要的部分——合约。这是描述上述组件之间所有交互的接口。 总结理论部分:
- View 知道 Presenter;
- Presenter了解View和Model(Repository);
- 自行建模;
- 契约控制着它们之间的相互作用。
MainContract
:
public interface MainContract {
interface View {
void showText();
}
interface Presenter {
void onButtonWasClicked();
void onDestroy();
}
interface Repository {
String loadMessage();
}
}
现在,我们只是重点介绍未来应用程序的 3 个组件以及它们将做什么。 接下来我们将描述存储库:
public class MainRepository implements MainContract.Repository {
private static final String TAG = "MainRepository";
@Override
public String loadMessage() {
Log.d(TAG, "loadMessage()");
/** Здесь обращаемся к БД or сети.
* Я специально ничего не пишу, чтобы не загромождать пример
* DBHelper'ами и прочими не относяшимеся к теме an objectми.
* Поэтому я буду возвращать строку Сосисочная =)
*/
return "Сосисочная у Лёхи»;
}
}
一切都很清楚,只是加载和卸载数据。 接下来是主讲人:
public class MainPresenter implements MainContract.Presenter {
private static final String TAG = "MainPresenter";
//Компоненты MVP applications
private MainContract.View mView;
private MainContract.Repository mRepository;
//Сообщение
private String message;
//Обрати внимание на аргументы конструктора - мы передаем экземпляр View, а Repository просто создаём конструктором.
public MainPresenter(MainContract.View mView) {
this.mView = mView;
this.mRepository = new MainRepository();
Log.d(TAG, "Constructor");
}
//View сообщает, что кнопка была нажата
@Override
public void onButtonWasClicked() {
message = mRepository.loadMessage();
mView.showText(message);
Log.d(TAG, "onButtonWasClicked()");
}
@Override
public void onDestroy() {
/**
* Если бы мы работали например с RxJava, в этом классе стоило бы отписываться от подписок
* Кроме того, при работе с другими методами асинхронного андроида,здесь мы боремся с утечкой контекста
*/
Log.d(TAG, "onDestroy()");
}
}
你还记得我写过关于手鼓跳舞和生命周期的文章吗?Presenter和View的生命周期一样长,在开发复杂的用户场景时,我建议您复制Presenter中的所有View回调并在适当的时刻调用它们,复制Activity/Fragment的生命周期,以便及时了解什么需要使用当前挂在“中间层”中的数据来完成。 最后,查看:
public class MainActivity extends AppCompatActivity implements MainContract.View {
private static final String TAG = "MainActivity";
private MainContract.Presenter mPresenter;
private Button mButton;
private TextView myTv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Создаём Presenter и в аргументе передаём ему this - эта Activity расширяет интерфейс MainContract.View
mPresenter = new MainPresenter(this);
myTv = (TextView) findViewById(R.id.text_view);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.onButtonWasClicked();
}
});
Log.d(TAG, "onCreate()");
}
@Override
public void showText(String message) {
myTv.setText(message);
Log.d(TAG, "showMessage()");
}
//Вызываем у Presenter метод onDestroy, чтобы избежать утечек контекста и прочих неприятностей.
@Override
public void onDestroy() {
super.onDestroy();
mPresenter.onDestroy();
Log.d(TAG, "onDestroy()");
}
}
这是怎么回事?
- Activity,也称为 View,
onCreate()
在方法中创建 Presenter 实例并将其自身传递给其构造函数。 - 当创建Presenter时,它显式接收一个View并创建一个Repository实例(顺便说一下,可以将其做成Singleton)
- 当按下按钮时,视图会敲击演示者并说:“按钮已按下。”
- 演示者转向存储库:“给我下载这个垃圾。”
- 存储库加载“内容”并将其传递给演示者。
- 演示者转向视图:“这是给你的数据,画出来”
GO TO FULL VERSION