Chuyển đến nội dung chính

Giới thiệu về mô hình MVP trên Android

 MVP là một mô hình kiến trúc hướng giao diện người dùng, được thiết kế để tạo thuận lợi cho việc kiểm thử đơn vị (unit testing) và tăng tính tách biệt giữa tầng dữ liệu và tầng hiển thị dữ liệu trong mô hình MVC. Đây là mô hình đang được áp dụng khá nhiều trong ứng dụng Android.

Mô hình MVP cho phép tách tầng trình diễn (Presenter) ra khỏi tầng dữ liệu (Model), vì vậy tương tác với giao diện được tách biệt với cách chúng ta biểu diễn nó trên màn hình (View), hay nói cách khác, tất cả logic  sẽ được tách ra và đưa vào tầng trình diễn (Presenter). Thiết kế lý tưởng nhất là với cùng một logic được áp dụng cho nhiều View khác nhau và hoán đổi được cho nhau.


1. Tìm hiểu chi tiết


Có rất nhiều biến thể cũng như phương pháp triển khai MVP, tất cả mọi người có thể điều chỉnh mô hình này tùy theo nhu cầu và cách họ cảm thấy thoải mái hơn. Nhưng tất cả vẫn phải dựa vào các quy tắc chung trên Model - View - Prensenter.

  • Model: Cái này thì các bạn rất quen thuộc rồi, nó không có gì khác với các mô hình khác, dùng để mô tả, chứa dữ liệu . Ví dụ ta có model Animal, Bike …

  • View: Thường được implement bởi một Activity , Fragment, View ... tùy thuộc vào cấu trúc ứng dụng, View này sẽ chứa một thuộc tính là một lớp Presenter.

  • Presenter: Tầng trình diễn có trách nhiệm như một cầu nối giữa View và Model. Nó lấy dữ liệu từ Model, định dạng và trả về cho View. Nhưng không giống như MVC, nó cũng quyết định những gì sẽ xảy ra khi người dùng tương tác với View, hay nói cách khác nó hàm chứa logic ứng dụng. Lý tưởng nhất Presenter nên được cung cấp bởi một Dependency Injection framewok như Dagger, nhưng trong trường hợp ứng dụng không sử dụng một thư viện hay framework như vậy ta hoàn toàn có thể tạo ra các đối tượng Presenter.


2. Lý do nên dùng


  • Điều đầu tiên mà chúng ta có thể dễ dàng nhận thấy là MVP phân chia các lớp một cách rành mạch so với MVC. Trong mô hình MVC, View và Model có thể tương tác lẫn nhau tức là chúng ta thường có xu hướng đưa nhiều các xử lý bên ngoài vào View. Hệ quả là View sẽ chứa rất nhiều các xử lý liên quan đến business logic và data logic. Và như vậy chúng ta cần phải phân tách 2 lớp xử lý này một cách rành mạch giống như MVP đã làm. 

  • Trong quá trình phát triển phần mềm, View là lớp mà có khả năng sẽ thay đổi nhiều nhất nên việc phân tách sẽ giúp thay đổi View một cách độc lập mà không ảnh hướng đến các thành phần khác.

  • Với mô hình MVP, việc viết Unit Tests sẽ đơn giản hơn rất nhiều. Bởi vì giờ đây Presenter và Model layer sẽ thuần là code java xử lý logic

  • Có thể giúp giảm thiểu lượng code trong ứng dụng cũng như gộp các xử lý, logic trong ứng dụng vào cùng một nơi. 


3. Demo thử màn Login


Mình sẽ cùng các bạn làm một demo cơ bản về xử lý màn Login theo mô hình MVP


Bước 1: Tạo Model

User.class

public class User {
    public String username;
    public String password;
    
    public User(String username, String password) {
        this.username = username;
        this.password = password;    
    }
    
    public String getUsername() {
        return username;    
    }
    
    public void setUsername(String username) {
        this.username = username;    
    }
    
    public String getPassword() {
        return password;    
    }
    
    public void setPassword(String password) {
        this.password = password;    
    }
}

Bước 2: Tạo 1 interface tên là LoginView chứa các phương thức tác động tới giao diện

LoginView.class

public interface LoginView {
    void loginFail();
    
    void loginSuccessful();
    
    void goHome();
}

Bước 3: Tạo các phương thức xử lý dữ liệu trong class LoginPresenter

LoginPresenter.class

public class LoginPresenter {

    LoginView loginView;
    public LoginPresenter(LoginView loginView) {
        this.loginView = loginView;    
    }
        
    public void login(String username, String password) {
       if (username.equalsIgnoreCase("admin") 
           && password.equalsIgnoreCase("admin")) {                    
           loginView.loginSuccessful();                
           loginView.goHome();            
       } else {                
           loginView.loginFail();            
       }        
     }   
      
}

Bước 4: Cuối cùng, ta bắt các sự kiện và xử lý ở class LoginActivity

LoginActivity.class

public class LoginActivity extends AppCompatActivity implements LoginView, View.OnClickListener {

    private EditText edtUsername;     
    private EditText edtPassword;     
    private Button btnLogin;     
    LoginPresenter loginPresenter;

    @Override 
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);        
        setContentView(R.layout.activity_main);        
        loginPresenter = new LoginPresenter(this);        
        initView();        
        initClick();    
    }
    
    public void initView() {        
        edtUsername = findViewById(R.id.edtUsername);        
        edtPassword = findViewById(R.id.edtPassword);        
        btnLogin = findViewById(R.id.btnLogin);    
    }
    
    public void initClick() {        
        btnLogin.setOnClickListener(this);    
    }
    
    @Override
    public void loginSuccessful() {
        Toast.makeText(this, "Login Thanh Cong!!",
                        Toast.LENGTH_SHORT).show();    
    }
        
    @Override
    public void loginFail() {
        Toast.makeText(this, "Login Fail!!",
                        Toast.LENGTH_SHORT).show();
    }
                        
     @Override
     public void goHome() {        
         startActivity(new Intent(this, HomeActivity.class));    
     }
     
     @Override
     public void onClick(Viewview) {
         if (view.getId() == R.id.btnLogin) {
            String username = edtUsername.getText().toString();
            String password = edtPassword.getText().toString();            
            loginPresenter.login(username, password);        
         }    
     }
     
}

4. Kết luận


Mô hình MVP đến nay vẫn đang được dùng khá phổ biến. Vấn đề quan trọng bạn cần nhớ là Presenter sẽ làm công việc logic. Ở một số hệ thống người ta còn dùng thêm các interactor, tuy nhiên bản chất vẫn thế. Mối liên hệ giữa view là presenter là 1-1. Nhưng có một lưu ý bạn cần chú ý là

 Nhược điểm lớn nhất của mô hình MVP là theo thời gian, Presenter sẽ dần lớn lên do bị thêm các business logic rải rác. Người dùng sẽ rất khó để kiểm soát và chia nhỏ code khi Presenter đã quá lớn.

  

GitHub

Nhận xét

Bài đăng phổ biến từ blog này

NHỮNG WIDGET THƯỜNG DÙNG TRONG FLUTTER

 https://baoflutter.com/nhung-widget-thuong-dung-trong-flutter/ Trong bài viết trước về  cách xây dựng màn hình ứng dụng Flutter , các bạn biết rằng các màn hình ứng dụng được tạo ra bởi các widget ghép lại với nhau. Vì vậy việc hiểu và sử dụng các Widget là rất quan trọng. Vì vậy trong bài viết này, tôi sẽ giới thiệu cho các bạn về những widget quan trọng trong Flutter. Hầu hết các Widget đều có các phần sau đây: + Đặc tính của Widget như : color, theme, height, weight, decoration, onTap, onPressed + Liên kết với các Widget khác với từ khoá: child, children, home hoặc body Ví dụ : 1 2 3 4 5 6 Container ( color : Colors . blue , height : 300 , weight : 300 , child : Text ( "Widget con" ) , ) Khi làm một số App cơ bản, bạn sẽ nắm chắc được cách sử dụng các Widget hay dùng. MaterialApp – Là widget rất liện lợi, cung cấp các widget cho việc xây dựng ứng dụng sử dụng thư viện Material Design UI của google. – Widget này được sử dụng trong hàm build đầu tiên của hầu hết các ứn...

Các bước cơ bản sử dụng Retrofit để thao tác với API và MVP

 Cài đặt  Retrofit //Retrofit implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' Cài đặt Gson implementation 'com.google.code.gson:gson:2.8.9' Cài thư viện Okhttp implementation 'com.squareup.okhttp3:okhttp:3.12.0' Sử dụng Gson ở trong project: 1. Tạo class App import android.app.Application ; import com.google.gson.Gson ; public class App extends Application { private static App mSelf ; private Gson mGSon ; public static App self () { return mSelf ; } @Override public void onCreate () { super .onCreate() ; mSelf = this; mGSon = new Gson() ; } public Gson getGSon () { return mGSon ; } } 2. Chỉnh file AndroidManifest: <? xml version ="1.0" encoding ="utf-8" ?> <manifest xmlns: android ="http://schemas.android.com/apk/res/android" xmlns: tools ="http://schemas.android....

Cấu trúc cơ bản layout trong Flutter