Android通過登錄註冊demo詳細解讀MVP思想

MVP模式

簡稱:MVP 全稱:Model-View-Presenter ;MVP 是從經典的模式MVC演變而來,它們的基本思想有相通的地方:Controller/Presenter負責邏輯的處理,Model提供數據,View負責顯示。

這張圖可以很清晰的看出MVP各層的職責,簡單來說

M層,即Model數據模型層,主要用來提供數據

V層,即VIew視圖層,用來展示視圖-------由Activity充當

P層,即preserter邏輯層,他是VIew層和Model層的橋樑,也是MVP模式的特點

MVP模式有哪些優點呢

 MVP模式是由MVC模式演化而來,在MVC模式中,Activity即充當了View又充當了Controller,這樣就導致Activity中的代碼可能會非常的臃腫,MVP模式就很好的解決了這個問題。

具體的優點:

1、模型與視圖完全分離,我們可以修改視圖而不影響模型

2、可以更高效地使用模型,因爲所有的交互都發生在一個地方--Presenter內部

3、我們可以將一個Presenter用於多個視圖,而不需要改變Presenter的邏輯。這個特性非常的有用,因爲視圖的變化總是比模型的變化頻繁。

4、如果我們把邏輯放在Presenter中,那麼我們就可以脫離用戶接口來測試這些邏輯(單元測試)

如何使用MVP

既然MVP模式這麼好用,那我們應該如何使用呢,接下來通過一個用戶登錄的demo來解析MVP模式

項目分包:

這裏主要分成了di和ui兩個包,di處理數據邏輯即M層和P層,ui處理頁面即V層。

創建契約類

我個人認爲創建契約類的方法非常好,幫助我們管理MVP中的接口,一目瞭然。

契約類的代碼如下

public interface IContract {
    public interface IView{
        void ShowData(String msg);
    }
    public interface IPresenter<IView>{
        void resqusetMesg(String name,String pwd);
        void attachView(IView iView);
        void deattachView(IView iView);
    }
    public interface IModel{
        public interface CallBack{
            void responseData(String msg);
        }
        void requestData(String name,String pwd,CallBack callBack);
    }
}

非常容易可以看出,這一個接口託管了MVP三層的接口

Activity中

剛纔已經介紹過了,在MVP中Acticity主要負責的是view的操作

所以我們的Acticity需要實現View的接口,重寫View中的方法

到這裏Activity如下

public class MainActivity extends AppCompatActivity implements IContract.IView {
       @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        }
       @Override
    public void ShowData(String msg) {
        }

之後我們的view層應該與p層進行關聯,也就是我們的Activity中需要持有p層的引用

private IContract.IPresenter presenter;

 剛剛說過,p層主要是邏輯層,處理View層的數據

所以當我們點擊按鈕之後,應該把輸入框中的內容傳到P層中進行非空判斷或者其他的邏輯判斷

而且P層要和View進行關聯,所以在持有P層的引用之後,應該調用P層的方法與View進行關聯

        //綁定當前的視圖
        presenter.attachView(this);

所以onCreate中如下

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        presenter = new PresenterImpl();
        //綁定當前的視圖
        presenter.attachView(this);
        name = findViewById(R.id.text_name);
        pwd = findViewById(R.id.text_pwd);
        button = findViewById(R.id.btn_login);
        //點擊按鈕獲取文本內容
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String name = MainActivity.this.name.getText().toString();
                String pwd = MainActivity.this.pwd.getText().toString();
                //傳到P層
                presenter.resqusetMesg(name,pwd);
            }
        });
    }

 之後我們再看重寫的方法

Activity是負責View的,也就是UI,重寫的方法也就是更新UI的方法

所以我們重寫的方法中代碼如下

 @Override
    public void ShowData(final String msg) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();
            }
        });

    }

 之後我們重寫onDestroy方法,銷燬視圖

 @Override
    protected void onDestroy() {
        presenter.deattachView(this);
        super.onDestroy();
    }

到這裏Activity中的所有代碼就完成了

Activity中的所有代碼如下: 

public class MainActivity extends AppCompatActivity implements IContract.IView {
    private IContract.IPresenter presenter;
    private EditText name;
    private EditText pwd;
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        presenter = new PresenterImpl();
        presenter.attachView(this);
        name = findViewById(R.id.text_name);
        pwd = findViewById(R.id.text_pwd);
        button = findViewById(R.id.btn_login);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String name = MainActivity.this.name.getText().toString();
                String pwd = MainActivity.this.pwd.getText().toString();
                presenter.resqusetMesg(name,pwd);
            }
        });
    }

    @Override
    public void ShowData(final String msg) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this,msg,Toast.LENGTH_SHORT).show();
            }
        });

    }

    @Override
    protected void onDestroy() {
        presenter.deattachView(this);
        super.onDestroy();
    }
}

P層的實現類

首先先實現P層的接口,重寫裏面的方法

public class PresenterImpl implements IContract.IPresenter<IContract.IView> {
    @Override
    public void resqusetMesg(String name, String pwd) {
    }
    @Override
    public void attachView(IContract.IView iView) {
    }
    @Override
    public void deattachView(IContract.IView iView) {
    }

}

P層就是view層和model層的一個橋樑

所以在P層中需要持有VIew層和Model層的引用,並且定義一個弱引用防止內存泄漏

    private IContract.IView iView;
    private IContract.IModel iModel;
    private WeakReference<IContract.IView> iViewWeakReference;
    private WeakReference<IContract.IModel> iModelWeakReference;

 接下來,看一下重寫的方法的作用

首先  resqusetMesg 方法,用來接收View傳過來的數據,並進行邏輯操作

這裏主要思路是先進行非空判斷,如果不爲空的話到Model層中去請求數據,然後通過接口回調把結果返回到View層

所以這個方法中的代碼如下

 @Override
    public void resqusetMesg(String name, String pwd) {
        if (name !=null){
            iModel.requestData(name, pwd, new IContract.IModel.CallBack() {
                @Override
                public void responseData(String msg) {
                    iView.ShowData(msg);
                }
            });
        }
    }

接下來  attachView 方法

這個方法的主要作用就是讓P層和VIew層建立聯繫

代碼如下:

 @Override
    public void attachView(IContract.IView iView) {
        this.iView = iView;
        iModel = new ModelImpl();
        iModelWeakReference = new WeakReference<>(iModel);
        iViewWeakReference = new WeakReference<>(iView);
    }

 最後 deattachView 方法

顯而易見也就是銷燬View的方法

@Override
    public void deattachView(IContract.IView iView) {
        iViewWeakReference.clear();
        iModelWeakReference.clear();
    }

至此P層就全部寫完了

P層的全部代碼如下 :

public class PresenterImpl implements IContract.IPresenter<IContract.IView> {
    private IContract.IView iView;
    private IContract.IModel iModel;
    private WeakReference<IContract.IView> iViewWeakReference;
    private WeakReference<IContract.IModel> iModelWeakReference;
    @Override
    public void resqusetMesg(String name, String pwd) {
        if (name !=null){
            iModel.requestData(name, pwd, new IContract.IModel.CallBack() {
                @Override
                public void responseData(String msg) {
                    iView.ShowData(msg);
                }
            });
        }
    }

    @Override
    public void attachView(IContract.IView iView) {
        this.iView = iView;
        iModel = new ModelImpl();
        iModelWeakReference = new WeakReference<>(iModel);
        iViewWeakReference = new WeakReference<>(iView);
    }

    @Override
    public void deattachView(IContract.IView iView) {
        iViewWeakReference.clear();
        iModelWeakReference.clear();
    }
}

M層的實現類

Model層是數據模型層,也就是主要負責請求數據的

首先先實現Model層的接口,重寫裏面的方法

public class ModelImpl implements IContract.IModel {

    @Override
    public void requestData(String name, String pwd, CallBack callBack) {

    }

}

之後我們通過OKHttp訪問網絡數據,也可以根據需求選擇其他的網絡請求框架

通過post請求,將我們拿到的用戶名和密碼到網上進行查詢,並將查詢到的結果返回

Model層的所有代碼如下 :

public class ModelImpl implements IContract.IModel {

    @Override
    public void requestData(String name, String pwd, final CallBack callBack) {
        String url = "https://www.zhaoapi.cn/user/login";
        OkHttpClient okHttpClient = new OkHttpClient
                .Builder()
                .writeTimeout(15, TimeUnit.SECONDS)
                .readTimeout(15, TimeUnit.SECONDS)
                .build();
        FormBody build = new FormBody
                .Builder()
                .add("mobile", name)
                .add("password", pwd)
                .build();
        Request request = new Request.Builder().url(url).post(build).build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String msg = response.body().string();
                callBack.responseData(msg);
            }
        });
    }
}

思路整理

1.首先先寫一個契約類,管理MVP的全部接口

2.讓MainActivity繼承View的接口,重寫方法

3.MainActivity持有P層的引用,點擊按鈕把獲取到的內容傳到P層進行邏輯操作

4.寫P層的實現類,判斷內容,如果沒有問題把數據傳到M層

5.寫M層的實現類,主要進行請求數據的操作

6.請求成功,把結果返回View層展示

注意:內存泄漏的問題

 

希望這篇文章對你的MVP學習有所幫助

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章