JavaRush /Java 博客 /Random-ZH /面向儿童的 Android MVP

面向儿童的 Android MVP

已在 Random-ZH 群组中发布
当我开始作为一名 Android 开发者的旅程时,“移动应用架构”这个词让我深感困惑,Google 和 Habré 上的文章让我陷入了更大的沮丧——我看着书,什么也没看到。我想如果你正在阅读这篇文章,你已经不止一次地研究过这张图,并试图理解正在发生的事情: Android 中适合小孩子的 MVP - 1在我看来,理解移动开发中的架构方法的问题在于架构本身的抽象性。每个开发人员对于如何正确实现这个或那个模式都有自己的愿景。在互联网的英语领域中或多或少都可以找到 MVP 实施的不错例子,这并不奇怪。让我们简要了解一下什么是什么,然后继续看一个示例。 模型-数据级别。我不喜欢使用“业务逻辑”这个术语,所以在我的应用程序中我将其称为存储库,它与数据库和网络进行通信。 视图——显示级别。如果你不喜欢手鼓跳舞以及与生命周期交互,那么它将是ActivityFragmentCustom View 。让我提醒您,最初所有 Android 应用程序都从属于MVC结构,其中控制器ActivityFragmentPresenter是View和Model之间的一层。View 传输发生在它身上的事件,presenter 处理它们,如有必要,访问 Model 并将数据返回给 View 进行渲染。关于Android和一个具体的例子,我将重点强调重要的部分——合约。这是描述上述组件之间所有交互的接口。 总结理论部分:
  • View 知道 Presenter;
  • Presenter了解View和Model(Repository);
  • 自行建模;
  • 契约控制着它们之间的相互作用。
实际上,在示例本身中,为了实验的简单性,通过单击按钮,我们将从数据库加载一行并将其显示在 TextView。例如,数据库包含该市最好的餐馆的列表。 让我们从契约开始: 让我们创建一个接口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)
  • 当按下按钮时,视图会敲击演示者并说:“按钮已按下。”
  • 演示者转向存储库:“给我下载这个垃圾。”
  • 存储库加载“内容”并将其传递给演示者。
  • 演示者转向视图:“这是给你的数据,画出来”
就是这样,伙计们。PS 明确划分组件之间的职责非常重要。例如,在我的一个培训项目中,当单击按钮时,需要更改数据库中的数据。该模型由 POJO 类描述,我传递了有关视图位置的信息,该视图负责有关屏幕上对象的信息,Presenter 在列表中查找该对象并将其发送到存储库。一切看起来合乎逻辑吗?但我的导师指出了以下几点:存储库应该只进行写入和读取,它不应该从 POJO 中提取必要的信息并决定需要写入什么。演示者必须只向他提供要记录的信息,仅此而已。实现架构没有严格的框架:实验、尝试、寻找对你个人来说方便的东西。并且不要忘记向您的高级同志展示代码审查 =) 该示例可在 GitHub 上找到: https: //github.com/admitrevskiy/MVP_Example
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION