学习AndroidMVP以及优化

什么是MVP

M:Model 数据层(网络,数据库,文件存储等等…)
V:View UI层 View、Activity、Fragment/以及他们的子类
P:Presenter 中介(作用:将M层与V层进行关联,交互的中介)
下面实现一个登陆功能

MVP基本案例

  • 实例代码
    项目列表
    学习AndroidMVP以及优化_第1张图片
    HttpUtils
/**
 * @作者: hyc
 * @时间: 2019/12/2
 * @说明:模拟网络请求
 **/
public class HttpUtils {
    HttpResultListener resultListener;
    public HttpUtils(String userName, int password, HttpResultListener resultListener) {
        this.resultListener = resultListener;
        if (userName.equals("10000") && password == 123456) {
            resultListener.onResult("用户:10000   登录成功!");
        } else {
            resultListener.onResult("用户:10000   登录失败");
        }
    }
    public interface HttpResultListener {
        void onResult(String result);
    }
}

LoginModel

/**
 * @作者: hyc
 * @时间: 2019/12/2
 * @说明:M层,网络请求
 **/
public class LoginModel1 {
    public void login(String userName, int password, final HttpUtils.HttpResultListener httpResultListener) {
        HttpUtils httpUtils = new HttpUtils(userName, password, new HttpUtils.HttpResultListener() {
            @Override
            public void onResult(String result) {
                httpResultListener.onResult(result);
            }
        });
    }
}

LoginView

public interface LoginView1 {
    void loginResult(String result);
}

LoginPresenter

/**
 * @作者: hyc
 * @时间: 2019/12/2
 * @说明:与M、V交互的中介
 **/
public class LoginPresenter1 {
    LoginModel1 loginModel;
    LoginView1 loginView;
    public LoginPresenter(LoginView1 loginView) {
        this.loginModel = new LoginModel();
        this.loginView = loginView;
    }
    public void login(String userName, int password) {
        loginModel.login(userName, password, new HttpUtils.HttpResultListener() {
            @Override
            public void onResult(String result) {
                if (loginView != null) {
                    loginView.loginResult(result);
                }
            }
        });
    }
}

MainActivity

public class MainActivity extends AppCompatActivity implements LoginView1 {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_login).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                LoginPresenter1 loginPresenter = new LoginPresenter1(MainActivity.this);
                loginPresenter.login("10000",123456);
            }
        });
    }
    @Override
    public void loginResult(String result) {
        TextView textView = findViewById(R.id.tv_result);
        textView.setText(result);
    }
}

R.layout.activity_main

<androidx.constraintlayout.widget.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=".MainActivity">
    <Button
        android:id="@+id/btn_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="登录请求"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/tv_result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        android:textSize="15sp"
        android:layout_marginTop="10dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn_login"
        />
androidx.constraintlayout.widget.ConstraintLayout>

运行项目点击登录
学习AndroidMVP以及优化_第2张图片

  • 介绍
    // MVP实现 -> 简单案例 -> 分层次设计 ->基本实现
    // 团队开发
    // V层 -> MainActivity -> LoginView
    // M层 -> 数据层(网络请求、数据库、文件等…)-> LoginModel
    // P层 ->需要新建 -> LoginPresenter
    // 总结:缺点(类结构复杂,接口多),优点(结构清晰,维护性强,有利于团队开发,模块维护,功能扩展,降低开发成本)
    ** // 特别适合大型项目,团队开发**

优化第一步

分析问题:当Activity关闭的时候,而数据请求依然在进行,需要解除UI层与数据层的关联
解决方案:方法绑定、解绑
attachView ->绑定 、detachView -> 解绑
把之前创建的LoginModel1、LoginPresenter1、LoginView1复制到另一个包下。
项目列表如下学习AndroidMVP以及优化_第3张图片
修改LoginPresenter2

public class LoginPresenter2 {
    LoginModel2 loginModel;
    LoginView2 loginView;
    public LoginPresenter2() {
        this.loginModel = new LoginModel2();
    }
    //绑定
    public void attachView(LoginView2 loginView) {
        this.loginView = loginView;
    }
    //解绑
    public void detachView() {
        this.loginView = null;
    }
    public void login(String userName, int password) {
        loginModel.login(userName, password, new HttpUtils.HttpResultListener() {
            @Override
            public void onResult(String result) {
                if (loginView != null) {
                    loginView.loginResult(result);
                }
            }
        });
    }
}

MainActivity修改

public class MainActivity extends AppCompatActivity implements LoginView2 {
    private LoginPresenter2 loginPresenter2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_login).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                loginPresenter2 = new LoginPresenter2();
                loginPresenter2.attachView(MainActivity.this);
                loginPresenter2.login("10000", 123456);
            }
        });
    }
    @Override
    public void loginResult(String result) {
        TextView textView = findViewById(R.id.tv_result);
        textView.setText(result);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        loginPresenter2.detachView();
    }
}

运行项目,结果一样。

优化第二步

分析问题:
现在写一个功能,没啥问题,如果功能多了,绑定和解除绑定会很烦,为了统一管理绑定
解决方法:抽象类(把公共抽取出来) -> BasePresenter
重复上一步复制操作
项目列表如下
学习AndroidMVP以及优化_第4张图片
新建BasePresenter

public abstract class BasePresenter {
    private LoginView3 loginView;
    //绑定
    public void attachView(LoginView3 loginView) {
        this.loginView = loginView;
    }
    //解绑
    public void detachView() {
        this.loginView = null;
    }
    public LoginView3 getLoginView() {
        return loginView;
    }
}

修改LoginPresenter

public class LoginPresenter3 extends BasePresenter {
    LoginModel3 loginModel;
    public LoginPresenter3() {
        this.loginModel = new LoginModel3();
    }
    public void login(String userName, int password) {
        loginModel.login(userName, password, new HttpUtils.HttpResultListener() {
            @Override
            public void onResult(String result) {
                if (getLoginView() != null) {
                    getLoginView().loginResult(result);
                }
            }
        });
    }
}

再修改MainActivity

public class MainActivity extends AppCompatActivity implements LoginView3 {
    private LoginPresenter3 loginPresenter3;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_login).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                loginPresenter3 = new LoginPresenter3();
                loginPresenter3.attachView(MainActivity.this);
                loginPresenter3.login("10000", 123456);
            }
        });
    }
    @Override
    public void loginResult(String result) {
        TextView textView = findViewById(R.id.tv_result);
        textView.setText(result);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        loginPresenter3.detachView();
    }
}

运行项目,结果一样

优化第三步

分析问题:BasePresenter抽象类写死了,只有LoginView,可能还会有登录或者注册,或者获取验证码,
希望能动态抽象

解决方案:BaseView解决
重复复制操作
项目列表如下
学习AndroidMVP以及优化_第5张图片
新建BaseView

public interface BaseView {
}

修改BasePresenter

public abstract class BasePresenter4 {
    private BaseView loginView;
    //绑定
    public void attachView(BaseView loginView) {
        this.loginView = loginView;
    }
    //解绑
    public void detachView() {
        this.loginView = null;
    }
    public BaseView getLoginView() {
        return loginView;
    }
}

修改LoginView4

public interface LoginView4 extends BaseView {
    void loginResult(String result);
}

修改LoginPresenter4

public class LoginPresenter4 extends BasePresenter4 {
    LoginModel4 loginModel;
    public LoginPresenter4() {
        this.loginModel = new LoginModel4();
    }
    public void login(String userName, int password) {
        loginModel.login(userName, password, new HttpUtils.HttpResultListener() {
            @Override
            public void onResult(String result) {
                if (getLoginView() != null) {
                    //这里强转
                    LoginView4 view= (LoginView4) getLoginView();
                    view.loginResult(result);
                }
            }
        });
    }
}

修改MainActivity

public class MainActivity extends AppCompatActivity implements LoginView4 {
    private LoginPresenter4 loginPresenter4;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_login).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                loginPresenter4 = new LoginPresenter4();
                loginPresenter4.attachView(MainActivity.this);
                loginPresenter4.login("10000", 123456);
            }
        });
    }
    @Override
    public void loginResult(String result) {
        TextView textView = findViewById(R.id.tv_result);
        textView.setText(result);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        loginPresenter4.detachView();
    }
}

运行项目,结果一样

优化第四步

分析问题:每次都需要强制类型转换。
解决方案:泛型设计
重复复制操作
项目列表如下
学习AndroidMVP以及优化_第6张图片
修改BasePresenter5

public abstract class BasePresenter5 <V extends BaseView5>{
    private V loginView;
    //绑定
    public void attachView(V loginView) {
        this.loginView = loginView;
    }
    //解绑
    public void detachView() {
        this.loginView = null;
    }
    public V getLoginView() {
        return loginView;
    }
}

修改LoginPresenter5

public class LoginPresenter5 extends BasePresenter5<LoginView5> {
    LoginModel5 loginModel;
    public LoginPresenter5() {
        this.loginModel = new LoginModel5();
    }
    public void login(String userName, int password) {
        loginModel.login(userName, password, new HttpUtils.HttpResultListener() {
            @Override
            public void onResult(String result) {
                if (getLoginView() != null) {
                    getLoginView().loginResult(result);
                }
            }
        });
    }
}

修改MainActivity

public class MainActivity extends AppCompatActivity implements LoginView5 {
    private LoginPresenter5 loginPresenter5;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_login).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                loginPresenter5 = new LoginPresenter5();
                loginPresenter5.attachView(MainActivity.this);
                loginPresenter5.login("10000", 123456);
            }
        });
    }
    @Override
    public void loginResult(String result) {
        TextView textView = findViewById(R.id.tv_result);
        textView.setText(result);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        loginPresenter5.detachView();
    }
}

运行项目,结果一样

优化第五步

分析问题:一个Activity需要去绑定与解除绑定,如果Activty和Fragment多了,很多代码冗余
解决方案:抽象类 ->抽象出绑定与解除绑定 ->BaseActivity
重复复制操作
项目列表如下
学习AndroidMVP以及优化_第7张图片
新建BaseActivity

public abstract class BaseActivity extends AppCompatActivity {
    private LoginPresenter6 presenter6;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        init();
    }
    private void init() {
        presenter6 = createPresenter();
        presenter6.attachView(createView());
    }
    public LoginPresenter6 getPresenter6() {
        return presenter6;
    }
    public abstract LoginPresenter6 createPresenter();
    public abstract LoginView6 createView();
    @Override
    protected void onDestroy() {
        super.onDestroy();
        presenter6.detachView();
    }
}

修改MainActivity

public class MainActivity extends BaseActivity implements LoginView6 {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_login).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
             getPresenter6().login("10000", 123456);
            }
        });
    }
    @Override
    public LoginPresenter6 createPresenter() {
        return new LoginPresenter6();
    }
    @Override
    public LoginView6 createView() {
        return this;
    }
    @Override
    public void loginResult(String result) {
        TextView textView = findViewById(R.id.tv_result);
        textView.setText(result);
    }
}

运行项目,结果一样

优化第六步

分析问题:BaseActivity还是写死了,未满足要求,只能用LoginPresenter6
解决方案:BaseActivity中抽象实现(BasePresenter和BaseView)

重复复制操作
项目列表如下
学习AndroidMVP以及优化_第8张图片
修改BaseActivity7

public abstract class BaseActivity7 extends AppCompatActivity {
    private BasePresenter7 presenter7;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        init();
    }
    private void init() {
        presenter7 = createPresenter();
        presenter7.attachView(createView());
    }
    public BasePresenter7 getPresenter7() {
        return presenter7;
    }
    public abstract BasePresenter7 createPresenter();
    public abstract BaseView7 createView();
    @Override
    protected void onDestroy() {
        super.onDestroy();
        presenter7.detachView();
    }
}

修改MainActivity

public class MainActivity extends BaseActivity7 implements LoginView7 {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_login).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                LoginPresenter7 presenter7 = (LoginPresenter7) getPresenter7();
                presenter7.login("10000", 123456);
            }
        });
    }
    @Override
    public LoginPresenter7 createPresenter() {
        return new LoginPresenter7();
    }
    @Override
    public LoginView7 createView() {
        return this;
    }
    @Override
    public void loginResult(String result) {
        TextView textView = findViewById(R.id.tv_result);
        textView.setText(result);
    }
}

运行项目,结果一样

优化第七步

分析问题:还需要强制类型转换
解决方案:泛型设计
重复复制操作
项目列表如下
学习AndroidMVP以及优化_第9张图片
修改BaseActivity8

public abstract class BaseActivity8<V extends BaseView8, P extends BasePresenter8<V>> extends AppCompatActivity {
    private P presenter8;
    private V view8;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        init();
    }
    private void init() {
        presenter8 = createPresenter();
        if (presenter8 == null) {
            throw new NullPointerException("presenter8 is null");
        }
        view8 = createView();
        if (view8 == null) {
            throw new NullPointerException("view8 is null");
        }
        presenter8.attachView(view8);
    }
    public P getPresenter8() {
        return presenter8;
    }
    public abstract P createPresenter();
    public abstract V createView();
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (presenter8 != null) {
            presenter8.detachView();
        }
    }
}

修改MainActivity

public class MainActivity extends BaseActivity8<LoginView8, LoginPresenter8> implements LoginView8 {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_login).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            getPresenter8().login("10000", 123456);
            }
        });
    }
    @Override
    public LoginPresenter8 createPresenter() {
        return new LoginPresenter8();
    }
    @Override
    public LoginView8 createView() {
        return this;
    }
    @Override
    public void loginResult(String result) {
        TextView textView = findViewById(R.id.tv_result);
        textView.setText(result);
    }
}

运行项目,结果一样

结言

我也是学习别人的自己总结记录下来,方便以后查看,俗话说,好记性不如烂笔头,文章写得不是很好,不喜勿喷,谢谢,有错误的地方,欢迎留言
源码入口github如果有帮助请帮我start 感谢!。

你可能感兴趣的:(Android学习专栏)