android開發筆記之MVP

MVP

下面這個圖,就解釋了MVP的數據流:
在這裏插入圖片描述
其中MVP,核心爲Presenter,View與Model沒有數據之間的交互。而MVC,核心爲Controller,View與Model有數據之間的交互。

所以MVP最大的優點就是Model與View之間的完全解耦。

MVP的權威資料

android 架構
https://github.com/googlesamples/android-architecture
todo-mvp 架構 github網站
https://github.com/googlesamples/android-architecture/tree/todo-mvp/

當你下載google官方的Demo後,建議你好好看看。

在這裏插入圖片描述

如果你一臉懵逼,可能你需要一些說明的資料:
Android官方MVP架構項目解析
http://www.android-doc.com/androiddocs/2017/0803/1218.html

這樣參照對比的看,你纔會看出來一點門道的。

MVP Demo 登錄操作

這是我參考官方Demo,再結合Android中用到的MVP模式
https://blog.csdn.net/weixin_28774815/article/details/80960779
一個文件,一行代碼的慢慢debug,才完成的Demo。

先看效果圖:
在這裏插入圖片描述
也就是輸入用戶名:test,密碼:1234,點擊CLICK,完成登錄操作,如果登錄成功,彈出登錄成功提示,或者彈出登錄失敗提示。

代碼的整件目錄如下:
在這裏插入圖片描述

先與界面佈局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MVPDemoMainActivity">

    <EditText
        android:id="@+id/user_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="input user name"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />

    <EditText
        android:id="@+id/password"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="input password"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/user_name"/>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click"
        app:layout_constraintTop_toBottomOf="@id/password"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>

然後,再直接從官網將BasePresenter.java和BaseView.java複製過來。

public interface BasePresenter {

    void start();

}
public interface BaseView<T> {

    void setPresenter(T presenter);

}

再定義一個IModel接口:

public interface  IModel {

}

然後實現LoginMode類,主要是實現一個登錄的操作:

public class LoginMode implements IModel {

    private String mUserName = "test";
    private String mPassWord = "1234";

    private LoginLisentener loginLisentener;

    public void login(String username, String password) {
        if (loginLisentener == null) {
            return;
        }

        if (mUserName.equals(username) && mPassWord.equals(password)){
            loginLisentener.onSeccess();
        } else {
            loginLisentener.onFails();
        }
    }

    public void setLoginLisentener(LoginLisentener loginLisentener) {
        this.loginLisentener = loginLisentener;
    }

    public interface LoginLisentener {
        void onSeccess();
        void onFails();
    }
}

下面再實現一個LoginContract類,這就是官方說的契約類。
在這個類中, 我們定義了View 接口,主要有二個接口,分別來表示登錄時成功和失敗的界面相關的操作。
再定義了Presenter 接口,主要是爲了執行登錄操作的總入口。

public class LoginContract {

    public interface View extends BaseView<Presenter> {

        void onLoginSeccess();

        void onLoginFails();

    }

    public interface Presenter extends BasePresenter {

        void onLogin(String name, String password);

    }

}

下面就是我們的核心類LoginPresenter,一般來說view和model都是其成員方法,一個構造方法,還有就是其定義的核心登錄操作接口onLogin,而start一般就是實現一些初始化操作:

public class LoginPresenter implements LoginContract.Presenter{

    private static final String TAG = "LoginPresenter";

    private final LoginContract.View mView;
    private  LoginMode loginMode;

    public LoginPresenter(final LoginContract.View mView) {
        this.mView = mView;
        this.loginMode = new LoginMode();
        loginMode.setLoginLisentener(new LoginMode.LoginLisentener() {
            @Override
            public void onSeccess() {
                mView.onLoginSeccess();
            }

            @Override
            public void onFails() {
                mView.onLoginFails();
            }
        });
    }

    @Override
    public void onLogin(String name, String password) {
        loginMode.login(name, password);
    }

    @Override
    public void start() {
        Log.i(TAG,"start");
    }
}

而最後,在MVPDemoMainActivity界面登錄時,我們就是隻要調用:loginPresenter.onLogin(getUserName(),getPassword());
就可以完成登錄的邏輯了。

public class MVPDemoMainActivity extends AppCompatActivity implements LoginContract.View{

    private static final String TAG = "MVPDemoMainActivity";

    private EditText user_name;
    private EditText password;
    private Button button;

    private LoginContract.Presenter loginPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mvpdemo_main);
        init();
    }

    private void init() {
        user_name = (EditText) findViewById(R.id.user_name);
        password = (EditText) findViewById(R.id.password);
        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                loginPresenter.onLogin(getUserName(),getPassword());
            }
        });

        loginPresenter = new LoginPresenter(this);
        loginPresenter.start();

    }

    private String getUserName(){
        return user_name.getText().toString();
    }

    private String getPassword(){
        return password.getText().toString();
    }

    @Override
    public void onLoginSeccess() {
        Toast.makeText(getApplicationContext(), "登陸成功!", Toast.LENGTH_LONG).show();
        Log.i(TAG,"onLoginSeccess");
    }

    @Override
    public void onLoginFails() {
        Toast.makeText(getApplicationContext(), "登陸失敗!", Toast.LENGTH_LONG).show();
        Log.i(TAG,"onLoginFails");
    }

    @Override
    public void setPresenter(LoginContract.Presenter presenter) {
        loginPresenter = presenter;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        this.loginPresenter = null;
    }

}

MVP+OKhttp Demo 獲取網絡信息

從最簡單的Android MVP講起
https://www.jianshu.com/p/4736ebe1114b
我們參考上面這個例子,來實現一個mvp+okhttp的例子

輸入一個網絡地址,獲取網絡信息,再顯示出來。
在這裏插入圖片描述

成功獲取網絡信息:
在這裏插入圖片描述

獲取網絡信息失敗:
在這裏插入圖片描述

具體代碼結構:
在這裏插入圖片描述

添加庫依賴 app\build.gradle

dependencies {
    implementation("com.squareup.okhttp3:okhttp:3.14.1")
    implementation("com.squareup.okio:okio:2.2.2")
}

在AndroidManifest.xml文件中添加網絡權限

<uses-permission android:name="android.permission.INTERNET"/>

MainView.java代碼:

public interface MainView {

    void getMessage(String message);
    void error();

}

MainModel.java代碼

public class MainModel {

    public Call getData(String url) {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();
        return client.newCall(request);
    }
}

MainPresenter.java代碼:

public class MainPresenter {

    private MainView mainView;
    private MainModel model;

    public MainPresenter(MainView mainView) {
        this.mainView = mainView;
        model=new MainModel();
    }

    public void getUrlData(String url){
        model.getData(url).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                mainView.error();
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                mainView.getMessage(response.body().string());
            }
        });
    }
}

MVPDemo02MainActivity .java

public class MVPDemo02MainActivity extends AppCompatActivity implements MainView{

    private TextView resultTextView;
    private MyHandler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mvpdemo02_main);
        init();
    }

    private void init() {
        Button button = (Button)findViewById(R.id.button);
        handler = new MyHandler(this);
        final EditText editText = (EditText)findViewById(R.id.et_url);
        resultTextView = (TextView)findViewById(R.id.tv_result);
        final MainPresenter presenter = new MainPresenter(this);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String url = editText.getText().toString();
                presenter.getUrlData(url);
            }
        });
    }

    @Override
    public void getMessage(String message) {
        Message msg = handler.obtainMessage(0, message);
        handler.sendMessage(msg);
    }

    @Override
    public void error() {
        Message msg = handler.obtainMessage(1, "error");
        handler.sendMessage(msg);
    }

    private static class MyHandler extends Handler {
        private WeakReference<MVPDemo02MainActivity> reference;

        private MyHandler(MVPDemo02MainActivity activity) {
            reference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            MVPDemo02MainActivity activity = reference.get();
            switch (msg.what) {
                case 0:
                    activity.resultTextView.setText(msg.obj.toString());
                    break;
                case 1:
                    activity.resultTextView.setText(msg.obj.toString());
                    break;
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章