【Android 架構之MVP】簡單的MVP搭建(上)

一、爲什麼使用MVP?

1. MVC傳統模式架構的劣勢

在這裏插入圖片描述
M層:數據層->包含(數據庫、文件、網絡、Javabean等等…)
V層:UI層->包含(View以及子類、Fragment以及子類、Activity以及子類)
C層:中介->作用(目的:就是將UI層和數據層進行解耦和,同時進行關聯)

我們在安卓中使用最多的就是MVC,相對來說他要求的技術難點較低,好寫,尤其是view層和control,安卓自身就已經做了一定的拆分。
在這裏插入圖片描述

缺點:

   視圖層(V層)和 邏輯層(C層)依然拆分不徹底,耦合性還是高,不利於維護、閱讀、迭代。

使用MVC的框架列舉:

   Android基於MVC的設計模式 , 百度地圖基於MVC的架構 等

Android基於MVC的設計模式:

   View層:xml ,
   C 層:Actvity ,
   M層:一個類中。

關於MVC各層之間關係所對應的設計模式

   View層,單獨實現了組合模式
   Model層和View層,實現了觀察者模式
   View層和Controller層,實現了策咯模式

2. 中介者設計模式

在這裏插入圖片描述
其實大家會發現這個統計部門很類似於中介 ,統計部門使得這些對象不必相互明顯作用。從而使它們可以降低耦合(鬆散耦合)。

當某些對象之間的作用發生改變時,不會立即影響其他的一些對象之間的作用。保證這些作用可以彼此獨立變化。中介者模式將多對多的相互作用轉化爲一對多的相互作用。中介者模式將對象的行爲和協作抽象化,把對象在小尺度的行爲上與其他對象的相互作用分開處理。

簡單來說 : 用一箇中介對象來封裝一系列的對象交互。中介者使各對象不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的交互。

中介者模式-應用場景?
.
當對象之間的交互操作很多且每個對象的行爲操作都依賴彼此時,爲防止在修改一個對象的行爲時,同時涉及修改很多其他對象的行爲,可以採用中介者模式來解決緊耦合問題。
.

如果還是對於中介者模式不瞭解,可以下載下面的代碼看一下
中介者模式代碼 Demo下載

3. MVP中模塊拆分化思想的優勢

在這裏插入圖片描述

Model:數據層.  負責與網絡層和數據庫層的邏輯交互.
 View :UI層.   顯示數據, 並向Presenter報告用戶行爲.
Presenter:從Model拿數據, 應用到UI層, 管理UI的狀態, 決定要顯示什麼, 響應用戶的行爲.

M層:數據層 --> 包含(數據庫、文件、網絡、Javabean等等…)
V層:UI層 --> 包含(View以及子類、Fragment以及子類、Activity以及子類)
P層:中介 --> 作用(目的:就是將UI層和數據層進行解耦和,同時進行關聯)

MVP設計目的:爲了將UI層和數據層進行分離

MVP模式的最主要優勢就是耦合降低, Presenter變爲純Java的代碼邏輯, 不再與Android Framework中的類,如Activity, Fragment等關聯, 便於寫單元測試。

二、MVP的使用

1. MVP角色劃分

抽象層
  • M層 ===》MvpModel
  • V層 ===》LoginView(UI交互接口)
  • P層 ===》MvpPresenter
具體實現層
  • M層 ===》LoginModel
  • V層 ===》MainActivity(或者:Fragment)
  • P層 ===》LoginPresenter

2. MVP代碼案例

抽象層
  • M層 ===》MvpModel
public abstract class MvpModel{
 
}
  • V層 ===》LoginView(UI交互接口)
public interface LoginView{
   void onLoginResult(String reslt);
}
  • P層 ===》MvpPresenter
public abstract class MvpPresenter{
 
  private LoginModel model;
  private LoginView view;
 
  public LoginView getView(){
    return view;
  }
 
  //V層綁定的方法
  public void attachView(LoginView view){
    this.view = view;
  }
 
  //V層解綁的方法
  public void detchView(){
    this.view=null;
  }
}
具體實現層
  • M層 ===》LoginModel
public class LoginModel extends MvpModel{
 
 public void login(String username,String password,
               final HttpUtils.OnHttpResultListener listener){
    Map<String,Object> params = new HashMap<>();
    params.put("phone",username);
    params.put("pwd",password);
 
    new HttpTask.Builder()
          .method("POST")
          .url("http://172.17.8.100/small/user/v1/login")
          .paramMap(params)
     .onHttpResultListener(new HttpUtils.OnHttpResultListener(){
            @Override
            public void onResult(String result){
                 listener.onResult(result);
            }
     }).build().execute();
  }
}
  • P層 ===》LoginPresenter
public class LoginPresenter extends MvpPresenter{
 
  private LoginModel model;
 
  public LoginPresenter(){
      this.model = new LoginModel();
  }
 
  public void login(String username,String password){
      this.model.login(username,password,
           new HttpUtils.OnHttpResultListener(){
             @Override
             public void onResult(String result){
                if(getView()!=null){
                     getView().onLoginResult(result);
                }
              }
            });
   }
}
  • V層 ===》MainActivity(或者:Fragment)
public class MainActivity extends AppCompatActivity 
                                        implements LoginView{
 
  private LoginPresenter presenter;
 
  @Override
  protected void onCreate(Bundle savedInstanceState){
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      this.presenter = new LoginPresenter();
      //綁定View
      this.presenter.attachView(this);
  }
 
   public void clickLogin(View view){
      this.presenter.login("15001194794","123");
   }
 
    @Override
    public void onLoginResult(String reslt){
        Toast.makeText(MainActivity.this,reslt,
                        Toast.LENGTH_LONG).show();
    }
 
   @Override
   protected void onDestroy(){
       super.onDestroy();
       presenter.detchView();
   }
}

三、MVP複雜案例

1. 複雜MVP角色劃分

接口層
  • M層 ===》MvpModel
  • V層 ===》MvpView
  • P層 ===》MvpPresenter
抽象層
  • M層 ===》BaseModel
  • V層 ===》BaseActivity
  • P層 ===》BasePresenter
具體實現層
  • M層 ===》LoginModel
  • V層 ===》LoginView、MainActivity(或者:Fragment)
  • P層 ===》LoginPresenter

2. 複雜MVP代碼案例

(1)接口層
  • M層 ===》MvpModel
public interface MvpModel {

}
  • V層 ===》MvpView
public interface MvpView {

}
  • P層 ===》MvpPresenter
public interface MvpPresenter <V extends MvpView>{
    //關聯視圖
    void attachView(V view);
    //分離視圖
    void detachView();
}
(2)抽象層
  • M層 ===》BaseModel
public abstract class BaseModel implements MvpModel {
    private Context context;

    public BaseModel(Context context) {
        this.context = context;
    }

    public Context getContext() {
        return context;
    }
}
  • V層 ===》BaseActivity

public abstract class BaseActivity<V extends MvpView, 
                       P extends MvpPresenter<V>> extends AppCompatActivity 
                       implements MvpView {
                       
    private P presenter;

    public abstract P createPersenter();
    
    public P getPresenter() {
        return presenter;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (presenter == null) {
            this.presenter = createPersenter();
        }
        if (presenter != null) {
            //關聯視圖
            this.presenter.attachView((V) this);
        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        //分離視圖
        this.presenter.detachView();
    }
}

  • P層 ===》BasePresenter
public class BasePresenter <V extends MvpView> implements MvpPresenter<V> {
    private V view;

    public V getView(){
        return view;
    }

    @Override
    public void attachView(V view){
        this.view = view;
    }

    @Override
    public void detachView(){
        this.view = null;
    }
}
(3)具體實現層
  • M層 ===》LoginModel

public class LoginModel extends BaseModel {

    public LoginModel(Context context) {
        super(context);
    }

    public void httpLogin(String username, String password, 
                          final HttpUtils.OnHttpResultListener listener) {
         //僞登錄                
        if (username.equals("12345")&&password.equals("000")){
            listener.onResult("登錄成功");
            return;
        }
//       本地接口
//        Map<String, Object> params = new HashMap<>();
//        params.put("phone", username);
//        params.put("pwd", password);
//
//        new HttpTask.Builder()
//                .method("POST")
//                .url("http://172.17.8.100/small/user/v1/login")
//                .paramMap(params)
//                .onHttpResultListener(new HttpUtils.OnHttpResultListener() {
//
//                    @Override
//                    public void onResult(Object result) {
//                        listener.onResult(result);
//                    }
//                }).build().execute();
    }
}

  • P層 ===》LoginPresenter
public class LoginPresenter extends BasePresenter<LoginView> {
    private LoginModel model;

    public LoginPresenter(Context mContext) {
        this.model = new LoginModel(mContext);
    }

    public void login(String username, String password) {
        this.model.httpLogin(username, password,
                             new HttpUtils.OnHttpResultListener() {

            @Override
            public void onResult(Object result) {
                getView().onLogin((String) result);
            }
        });
    }
}
  • V層 ===》LoginView、MainActivity(或者:Fragment)

LoginView.java

public interface LoginView extends MvpView {
    void onLogin(String result);

}

MainActivity.java


public class MainActivity extends BaseActivity<LoginView, LoginPresenter> 
                                                        implements LoginView {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getPresenter().login("12345", "000");
            }
        });
    }
    
    @Override
    public void onLogin(String result) {
        Toast.makeText(this, "返回內容:" + result, Toast.LENGTH_LONG).show();
    }

    @Override
    public LoginPresenter createPersenter() {
        return new LoginPresenter(this);
    }
}
發佈了22 篇原創文章 · 獲贊 23 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章