Android Architecture

Bài viết này giới thiệu cơ bản về các mô hình kiến trúc MVC, MVP, MVVM được sử dụng trong các dự án phát triển phần mềm cho nền tảng Android.

Mô hình MVC - Model View Controller

Mô hình thiết kế MVC chia một ứng dụng thành 3 phần chính: Model, View và Controller. Mỗi thành phần có nhiệm vụ riêng và độc lập với các thành phần khác. Domain Model và Controller Logic được tách riêng từ User Interface (View). mvc.png

Model

Model gồm tập các lớp đặc tả cho logic nghiệp vụ (business model) và các hoạt động truy cập dữ liệu (data model). Ngoài ra, model cũng định nghĩa các business rule cho dữ liệu, tức là, định nghĩa cách dữ liệu được thay đổi và thao tác.

View

View đại diện cho các thành phần giao diện người dùng (User Interface). View đảm nhận trách nhiệm hiển thị các dữ liệu nhận được từ Controller như là kết quả tới người dùng. Để làm được điều này, View thực hiện chuyển đổi dữ liệu trong các Model lên trên giao diện người dùng (User Interface).

Controller

Controller chịu trách nhiệm xử lý các yêu cầu (request) gửi đến. Controller nhận đầu vào từ người dùng thông qua View, sau đó xử lý dữ liệu của người dùng với sự giúp đỡ của Model, và trả lại kết quả cho View. Thông thường, Controller đóng vai trò là điều phối viên giữa View và Model.

Mô hình MVP - Model View Presenter

Mô hình này tương tự như mô hình MVC, trong đó, Controller đã được thay thế bởi Presenter. Mô hình MVP chia ứng dụng thành 3 phần chính: Model, View và Presenter. mvp.png

Model

Model đại diện tập các lớp mô tả business logic và data. Model cũng định nghĩa các business rule cho data có nghĩa là cách data được thay đổi và thao tác.

View

View đại diện cho các thành phần giao diện người dùng (UI). View đảm nhận trách nhiệm hiển thị các dữ liệu nhận được từ Controller như là kết quả tới người dùng. Để làm được điều này, View thực hiện chuyển đổi dữ liệu trong các Model lên trên giao diện người dùng (User Interface).

Presenter

Presenter có trách nhiệm xử lý tất cả các sự kiện UI cho View. Nó nhận đầu vào từ người dùng thông qua View, sau đó xử lý dữ liệu của người dùng với sự giúp đỡ của Model và trả lại kết quả cho View. Không giống như View và Controller, View và Presenter là hoàn toàn tách rời nhau và giao tiếp với nhau thông qua interface. Ngoài ra, Presenter không quản lý các lưu lượng yêu cầu đến như controller.

Những điểm chính về mô hình MVP

  • Người dùng tương tác với các View.
  • Có mối quan hệ 1-1 giữa View và Presenter, tức là một View được ánh xạ tới chỉ một Presenter.
  • View có một tham chiếu đến Presenter, nhưng không tham chiếu đến Model.
  • Cung cấp giao tiếp 2 chiều giữa View và Presenter.

Mô hình MVVM - Model View ViewModel

MVVM là viết tắt của Model-View-ViewModel. Mô hình này hỗ trợ ràng buộc dữ liệu 2 chiều giữa View và ViewModel. Điều này cho phép tự động truyền sự thay đổi bên trong trạng thái của ViewModel đến View. Thông thường, ViewModel sử dụng các observer pattern để thông báo (notify) những thay đổi trong ViewModel đến Model. mvvm.png

Model

Model gồm tập các lớp đặc tả cho logic nghiệp vụ (business model) và các hoạt động truy cập dữ liệu (data model). Ngoài ra, model cũng định nghĩa các business rule cho dữ liệu, tức là, định nghĩa cách dữ liệu được thay đổi và thao tác.

View

View đại diện cho các thành phần giao diện người dùng (UI). View đảm nhận trách nhiệm hiển thị các dữ liệu nhận được từ Controller như là kết quả tới người dùng. Để làm được điều này, View thực hiện chuyển đổi dữ liệu trong các Model lên trên giao diện người dùng (User Interface).

ViewModel

ViewModel chịu trách nhiệm cung cấp ra các phương thức, lệnh, và các thuộc tính (properties) khác để duy trì trạng thái của View, thao tác trên các Model như là kết quả của các hành động trên View, và kích hoạt các sự kiện trong chính View.

Những điểm chính về mô hình MVVM

  • Người dùng tương tác với các View.
  • Có mối quan hệ n-1 giữa View và ViewModel, tức là nhiều View có thể được ánh xạ tới một ViewModel.
  • View có một tham chiếu đến ViewModel, nhưng ViewModel không có thông tin về các View.
  • Hỗ trợ giao tiếp 2 chiều giữa View và ViewModel.

Áp dụng trong dự án Android

Vai trò chính của các thành phần Controller, Presenter, ViewModel trong mỗi mô hình là tương tự nhau, vì vậy, sau đây sẽ gọi chung chúng là "controller" khi implement chúng trong dự án Android.

Cách tiếp cận phổ biến khi áp dụng các mô hình này trong dự án Android là sử dụng các lớp Activity làm Controller, các lớp Fragment làm thành phần View. Thế nhưng cách cài đặt như vậy sẽ làm giảm tính linh hoạt và khả năng tái sử dụng code. Fragment và Activity cũng có giới hạn phạm vi của các animation biến đổi sẵn dùng. implement.png

Thành phần View - các lớp UI (ví dụ: LinearLayout)

Tầng View nên được cài đặt trong các lớp mà được kế thừa từ các phần tử view (ui) của android, chẳng hạn như LinearLayout hoặc ViewGroup.

  • Tái sử dụng tính năng độc lập của flow ứng dụng, Activity.
  • Giảm số lượng các Activity.
  • Không phụ thuộc vào các thành phần Controller.

Khai báo:

	public interface TopImagesListView {
    void setImage(List<Image> images);

    void logout();
    }

implement trong Activity:

	public class TopImagesListActivity extends EffectiveActivity TopImagesListView {
    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setUpView();
        presenter = createPresenter();
        presenter.create();
    }

    @Override
    public void setImage(List<Image> images) {
        adapter = new ImageRecyclerView(images);
        recyclerView.setAdapter(adapter);
    }

    @Override
    public void logout() {
        finish();
        startActivity(new Intent(this, LoginActivity.class));
    }
    ...
    }

Thành phần Controller

Các lớp controller nên là các lớp thuần Java, không nên kế thừa từ bất kỳ lớp android nào. Mặt khác, cũng giữ cho các lớp controller tách biệt với các Activity và Fragment sẽ cho phép tái sử dụng nó.

  • Controller giữ vai trò đơn giản làm thành phần kết dính giữa tầng View và Model.
  • Đẩy các event tới các Controller khác.
  • Tách biệt với các lớp Android để tái sử dụng.

Khai báo:

	public interface TopImagesListPresenter extends Presenter {
    void create();

    void setView(TopImagesListView view);
    }

Implement:

	public class TopImagesListPresenterImpl implements TopImagesListPresenter {
    private final TopImageListModel model;

    private TopImagesListView view;
    private List<Image> viewArticles;

    public TopImagesListPresenterImpl(TopImagesListView view) {
        this.view = view;
        this.model = new TopImageListModelImpl(
                TwitterCore.getInstance().getSessionManager().getActiveSession());
    }

    @Override
    public void create() {
        if (viewArticles == null) {
            viewArticles = new ArrayList<>();
            model.getMostRtImages(new Callback<List<Image>>() {
                @Override
                public void success(Result<List<Image>> result) {
                    viewArticles.addAll(result.data);
                    view.setImage(viewArticles);
                }

                @Override
                public void failure(TwitterException e) {
                    view.logout();
                }
            });
        } else {
            view.setImage(viewArticles);
        }
    }

    @Override
    public void setView(TopImagesListView view) {
        this.view = view;
    }
}

Thành phần Model

Khai báo:

	public interface TopImageListModel {
    void getMostRtImages(Callback<List<Image>> articles);
    }

Implement:

	public class TopImageListModelImpl implements TopImageListModel {

    @Override
    public void getMostRtImages(final Callback<List<Image>> callback) {
        client.getTimelineService().homeTimeline(200, true, true, true, true,
                new Callback<List<Tweet>>() {
                    @Override
                    public void success(Result<List<Tweet>> result) {
                        final List<Image> items = processTweets(result);
                        callback.success(items, null);

                    }

                    @Override
                    public void failure(TwitterException e) {
                        callback.failure(e);
                    }
                });
    }
}

Thành phần Entity

	public class Article implements Comparable<Article>, Parcelable {
        private final String title;
        private final String url;
        private final int retweetCount;
        private final String mediaUrl;

        public Article(String title, String url, int retweetCount, String mediaUrl) {
            this.title = title;
            this.url = url;
            this.retweetCount = retweetCount;
            this.mediaUrl = mediaUrl;
        }
    }

Tổng kết

Như vậy, phát triển một dự án Android theo mô hình kiến trúc sẽ giúp tách biệt các thành phần, dễ dàng tái sử dụng, bảo trì và mở rộng dự án.