JavaRush /Blog Java /Random-VI /MVP trong Android dành cho trẻ nhỏ

MVP trong Android dành cho trẻ nhỏ

Xuất bản trong nhóm
Khi tôi bắt đầu hành trình trở thành một nhà phát triển Android, cụm từ “Kiến trúc ứng dụng di động” đã khiến tôi vô cùng hoang mang, Google và các bài viết về Habré càng khiến tôi chán nản hơn - tôi nhìn vào cuốn sách và chẳng thấy gì cả. Tôi nghĩ nếu bạn đang đọc bài viết này, bạn đã nghiên cứu bức tranh này hơn một lần và cố gắng hiểu điều gì đang xảy ra: MVP trên Android dành cho các bạn nhỏ - 1Theo tôi, vấn đề hiểu cách tiếp cận kiến ​​​​trúc trong phát triển di động, nằm ở tính trừu tượng của chính kiến ​​​​trúc. Mỗi nhà phát triển có tầm nhìn riêng của mình về cách triển khai chính xác mẫu này hoặc mẫu kia. Ít nhiều ví dụ điển hình về việc triển khai MVP đã được tìm thấy trong khu vực nói tiếng Anh trên Internet, điều này không có gì đáng ngạc nhiên. Chúng ta hãy xem xét ngắn gọn những gì là những gì và chuyển sang một ví dụ. Mô hình - mức dữ liệu. Tôi không thích sử dụng thuật ngữ “logic nghiệp vụ”, vì vậy trong các ứng dụng của mình, tôi gọi nó là Kho lưu trữ và nó giao tiếp với cơ sở dữ liệu và mạng. Xem - mức độ hiển thị. Đó sẽ là Hoạt động , Đoạn hoặc Chế độ xem tùy chỉnh nếu bạn không thích nhảy múa với tambourine và tương tác với vòng đời. Hãy để tôi nhắc bạn rằng ban đầu tất cả các ứng dụng Android đều phụ thuộc vào cấu trúc MVC , trong đó Bộ điều khiểnHoạt động hoặc Đoạn . Presenter là một lớp giữa View và Model. Chế độ xem truyền các sự kiện xảy ra với nó, người trình bày sẽ xử lý chúng, nếu cần, truy cập vào Mô hình và trả về dữ liệu cho Chế độ xem để hiển thị. Liên quan đến Android và một ví dụ cụ thể, tôi sẽ nêu bật phần quan trọng - Hợp đồng. Đây là giao diện mô tả tất cả các tương tác giữa các thành phần trên. Tóm tắt phần lý thuyết:
  • Xem biết về Người trình bày;
  • Người trình bày biết về Chế độ xem và Mô hình (Kho lưu trữ);
  • Tự làm mẫu;
  • Hợp đồng chi phối sự tương tác giữa chúng.
Trên thực tế, bản thân ví dụ này, để đơn giản cho thử nghiệm, bằng cách nhấp vào nút, chúng tôi sẽ tải một hàng từ cơ sở dữ liệu và hiển thị nó trong TextView . Ví dụ: cơ sở dữ liệu chứa danh sách các nhà hàng tốt nhất trong thành phố. Hãy bắt đầu với hợp đồng: Hãy tạo một giao diện MainContract:


public interface MainContract {
    interface View {
        void showText();
    }

    interface Presenter {
        void onButtonWasClicked();
        void onDestroy();
    }

    interface Repository {
        String loadMessage();
    }
}
Hiện tại, chúng tôi chỉ nêu bật 3 thành phần của ứng dụng trong tương lai và chức năng của chúng. Tiếp theo chúng ta sẽ mô tả Kho lưu trữ:


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 "Сосисочная у Лёхи»;
    }
}
Mọi thứ đều rõ ràng với nó, chỉ cần tải và dỡ dữ liệu. Tiếp theo là Người trình bày:


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()");
    }
}
Bạn có nhớ tôi đã viết về việc khiêu vũ với trống lục lạc và vòng đời không? Trình trình bày tồn tại miễn là Chế độ xem của nó tồn tại, khi phát triển các kịch bản người dùng phức tạp, tôi khuyên bạn nên sao chép tất cả lệnh gọi lại Chế độ xem trong Trình bày và gọi chúng vào những thời điểm thích hợp, sao chép vòng đời Hoạt động/Phân đoạn, để hiểu kịp thời những gì cần được thực hiện với dữ liệu hiện đang treo trong “lớp xen kẽ”. Và cuối cùng, Xem:


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()");
    }
}
Chuyện gì đang xảy ra vậy?
  • Hoạt động, còn được gọi là Chế độ xem, onCreate()tạo một phiên bản Trình bày trong một phương thức và chuyển chính nó tới hàm tạo của nó.
  • Khi Người trình bày được tạo, nó sẽ nhận một Chế độ xem một cách rõ ràng và tạo một phiên bản Kho lưu trữ (nhân tiện, nó có thể được tạo thành Singleton)
  • Khi nhấn một nút, Chế độ xem sẽ gõ vào người trình bày và thông báo: “Nút đã được nhấn”.
  • Người trình bày quay sang Kho lưu trữ: “Tải xuống cái thứ nhảm nhí này cho tôi.”
  • Kho lưu trữ tải và phân phối “nội dung” cho Người trình bày.
  • Người thuyết trình quay sang View: “Đây là dữ liệu cho bạn, hãy vẽ nó”
Thế thôi các bạn. Tái bút Điều quan trọng là phải phân định rõ ràng trách nhiệm giữa các thành phần. Ví dụ, trong một trong những dự án đào tạo của tôi, khi nhấp vào nút, cần phải thay đổi dữ liệu trong cơ sở dữ liệu. Model được mô tả bởi một lớp POJO, tôi truyền thông tin về vị trí của view, nó chịu trách nhiệm về thông tin về đối tượng trên màn hình, Presenter tìm kiếm đối tượng này trong danh sách và gửi nó để ghi vào Repository. Mọi thứ có vẻ hợp lý? Nhưng người cố vấn của tôi đã chỉ ra những điều sau: Kho lưu trữ CHỈ nên viết và đọc, nó không được lấy thông tin cần thiết ra khỏi POJO và quyết định những gì nó cần viết. Người trình bày chỉ được cung cấp cho anh ta thông tin để ghi lại và không cung cấp gì thêm. Không có khuôn khổ nghiêm ngặt nào cho việc triển khai kiến ​​​​trúc: thử nghiệm, thử, tìm kiếm những gì thuận tiện cho cá nhân bạn. Và đừng quên cho các đồng chí cấp trên xem code review nhé =) Ví dụ có trên GitHub: https://github.com/admitrevskiy/MVP_Example
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION