推荐阅读:

Android MVC设计模式详解

Android 框架MVVM详解

Android 认识EventBus轻量级事件总线框架

Android 依赖注入库——Dagger2使用详解



    MVP模式属于UI框架模式的一种,随着UI技术的功能日益丰富,View层也履行着越来越多的职责。为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互,同时让Model只关系数据的处理,基于MVC概念的MVP(Model-View-Presenter)模式应运而生。为了更好的理解MVP,那就必须先了解MVC。了解了MVC后动手实践一个MVP的案例,然后进行总结。


MVP与MVC对比


(1)相通之处

    因为MVP是由经典的设计模式MVC演变而来,它们的基本思想有相通之处:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。

(2)MVC的缺陷

  • 在MVC模型里,更关注模型层(Model)的不变。因为一个模型层(Model)可以被多个视图层(View)重用,Model不依赖于View,但是View是依赖于Model的。
  • 在MVC模型里,视图层无法实现独立重用。视图层需要持有控制层Activity的引用才能进行UI引用。不仅如此,视图层(View)是可以直接访问模型层(Model)的数据,从而视图层不可避免会涉及一些业务逻辑。由于在View里实现的业务逻辑是无法被重用的,导致要更改和重用View变得比较困难。
  • 由于模型操作接口的不同,视图可能需要多次调用模型才能获得足够的显示数据,不必要的频繁访问未变化数据的,也损害一定性能。

(3)两者区别

    在MVP中视图层(View)不能直接访问模型层(Model),它们之间通过Presenter(Controller)来进行通信的。这一点很好的弥补了MVC的设计缺陷,使View与Model实现完全分离。View无法直接从Model中读取数据,所有的交互都发生在 Presenter层(Controller)。如下图所示:



MVP代码案例


CSDN下载本案例:http://download.csdn.net/download/csdn_aiyang/10194951


(1)实现的功能,如下图所示。

(2)Model 层 ,代码如下

LoginModel.class 接口

public interface LoginModel {    interface OnLoginListener {        void onLoginSuccess();        void onLoginFail();    }    void loginSubmit(String username, String password, OnLoginListener listener);}

UserInfo.class 

public class UserInfo implements LoginModel{    private String age;    private String name;    private String gender;    private String hobby;    public String getAge() {        return age;    }    public void setAge(String age) {        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getGender() {        return gender;    }    public void setGender(String gender) {        this.gender = gender;    }    public String getHobby() {        return hobby;    }    public void setHobby(String hobby) {        this.hobby = hobby;    }    @Override    public void loginSubmit(final String username, final String password, final OnLoginListener listener) {        //此次Handler制造延迟3秒和回调——纯属模仿网络请求。实际开发可以替换        new Handler().postDelayed(new Runnable() {            @Override            public void run() {                if (username.equals("1") && password.equals("1")) {                    listener.onLoginSuccess();                } else {                    listener.onLoginFail();                }            }        }, 2000);    }}

*弹框 Dialog.class

/** * 弹框工具类 */public class DialogUtil {    /**     *  显示基本Dialog     */    public static void showSimpleDialog(Context context, String title, String message , DialogInterface.OnClickListener clickListener) {        AlertDialog.Builder builder =new AlertDialog.Builder(context);//        builder.setIcon(R.mipmap.ic_launcher);        builder.setTitle(title);        builder.setMessage(message);        //监听事件        if (clickListener != null){            builder.setPositiveButton("确认",clickListener);        }else{            builder.setPositiveButton("确认",null);        }        builder.setNegativeButton("取消",null);        //设置对话框是可取消的        builder.setCancelable(true);        AlertDialog dialog=builder.create();        dialog.show();    }    protected static ProgressDialog progressDialog;    /**     * 显示进度条     * @param context     * @param msg     */    public static void showProgress(Context context,String msg){        if (progressDialog == null){            progressDialog = new ProgressDialog(context);        } else if (progressDialog.isShowing()){            progressDialog.dismiss();        }        progressDialog.setMessage(msg);        progressDialog.show();    }    /**     * 关闭进度条     */    public static void dismissProgress(){        if (progressDialog != null ){            if (progressDialog.isShowing()){                progressDialog.dismiss();            }        }    }}

(3)Presenter 层,代码如下

接口

public interface ILoginPresenter {    void loginSubmit(String username, String password);}

实现

/** * Created by aiyang on 2018/1/8. * 中介者——处理视图和模型 */public class LoginPresentImpl implements ILoginPresenter,LoginModel.OnLoginListener {    private LoginView mView;    private LoginModel mModel;    /**     * 构造函数进行实例化     * @param mView     * @param mModel     */    public LoginPresentImpl(LoginView mView, LoginModel mModel) {        this.mView = mView;        this.mModel = mModel;    }    /**     * 登陆方法     * @param username     * @param password     */    @Override    public void loginSubmit(String username, String password) {        mView.showProgress();        mModel.loginSubmit(username,password,this);//在模型中通过接口分解结果,并将回调方法暴露出来,可以做到抽离开Model对View的联系。    }    @Override    public void onLoginSuccess() {        mView.loginSuccess();    }    @Override    public void onLoginFail() {        mView.loginFail();        mView.hideProgress();    }}

(4)View 层  ,代码如下

/** * Created by aiyang on 2018/1/8. * UI接口 */public interface LoginView {    /**     * 显示进度条     */    void showProgress();    /**     * 隐藏进度条     */    void hideProgress();    /**     * 登录成功处理UI     */    void loginSuccess();    /**     * 登录失败处理UI     */    void loginFail();}

BaseActivity.class

/** * Created by aiyang on 2018/7/3. */public abstract class BaseActivity extends AppCompatActivity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_base);        FrameLayout contentView = findViewById(R.id.view_content);        LayoutInflater.from(this).inflate(setContentView(),contentView);        init(savedInstanceState);    }    /**     * 设置布局     * @return     */    protected abstract int setContentView();    /**     * 子类初始化     * @param savedInstanceState     */    protected abstract void init(Bundle savedInstanceState);    /**     * 设置标题     * @param str     */    protected void setTitle(String str){        if (str != null || !TextUtils.isEmpty(str)){            TextView title_view = findViewById(R.id.title);            title_view.setText(str);        }    }    /**     * 显示返回按钮     * @param show     */    protected void setBack(boolean show){        TextView back_view = findViewById(R.id.back);        if (show){            back_view.setVisibility(View.VISIBLE);            back_view.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View view) {                    finish();                }            });        }else{            back_view.setVisibility(View.INVISIBLE);        }    }    /**     * 普通页面跳转     */    protected void openActivity(Class<?> Action){        startActivity(new Intent(this,Action));    }}

LoginActivity.class

/** * Created by aiyang on 2018/7/3. * 登陆页面 */public class LoginActivity extends BaseActivity implements LoginView,View.OnClickListener{    EditText name;    EditText pwd;    Button submit;    ILoginPresenter presenter;    @Override    protected int setContentView() {        return R.layout.activity_login;    }    @Override    protected void init(Bundle savedInstanceState) {        setTitle("登录");        setBack(false);        initView();        presenter = new LoginPresentImpl(this,new UserInfo());    }    private void initView() {        name = findViewById(R.id.name);        pwd = findViewById(R.id.pwd);        submit =findViewById(R.id.submit);        submit.setOnClickListener(this);    }    @Override    public void onClick(View view) {        if (view.getId() == R.id.submit){            String account = name.getText().toString().trim();            String password =  pwd.getText().toString().trim();            if (!TextUtils.isEmpty(account) && !TextUtils.isEmpty(password)){                presenter.loginSubmit(account, password);            }else {                DialogUtil.showSimpleDialog(this,"错误提示","账户密码不能为空",null);            }        }    }    @Override    public void showProgress() {        DialogUtil.showProgress(this,"登陆中");    }    @Override    public void hideProgress() {        DialogUtil.dismissProgress();    }    @Override    public void loginSuccess() {        DialogUtil.showSimpleDialog(this, "登陆成功", "验证通过,是否进入到首页?", new DialogInterface.OnClickListener() {            @Override            public void onClick(DialogInterface dialogInterface, int i) {                openActivity(MainActivity.class);            }        });    }    @Override    public void loginFail() {        DialogUtil.showSimpleDialog(this,"错误提示","账户密码不正确",null);    }}

MainActivity.class

public class MainActivity extends BaseActivity{    @Override    protected int setContentView() {        return R.layout.activity_main;    }    @Override    protected void init(Bundle savedInstanceState) {        setTitle("首页");        setBack(true);    }}


(1)优点

  • 项目结构清晰,解耦程度高,每个功能相互之间独立,可单独测试。
  • 代码维护性高,代码出现Bug,能够快速定位。
  • 功能扩展性强,增加业务功能时,并不需要去修改原始代码,只需增加相应的业务代码即可。

(2)缺点


  • 出现大量的presenter,增加了项目类的数量,代码量增大,项目依然看起来臃肿,有时业务简单就直接一个Activity搞定了。
  • 有时Activity和presenter有强引用关系,使用不当的话,容易出现内存泄漏的问题。
  • presenter与 View 之间的联系过与紧密,一旦视图变更,presenter也随之变更。



CSDN下载:http://download.csdn.net/download/csdn_aiyang/10194951


MVP高级使用。结合RXJava\Retrofit\okHttp等框架使用。

Githup地址:https://github.com/aiyangtianci/MVPDemo



更多相关文章

  1. android实用代码片段
  2. Android(安卓)Handler 分析学习
  3. inflater在ListView中的使用
  4. Android(安卓)开机自动启动服务
  5. Android基于opencv进行图像识别并找出中心点和轮廓
  6. android Preference之android:dependency(列表依赖关系)
  7. Android全屏--两种activity的实现方式
  8. android背景选择器总结
  9. android下访问sd卡和网络的权限

随机推荐

  1. android自定义view 右侧字母导航
  2. 【Android即时通讯】Android(安卓)高仿微
  3. android 根据文件Uri获取图片url
  4. Android使用okhttp进行自制证书的双向SSL
  5. Android学习系列(27)--App缓存管理
  6. 基于容器原理(docker、lxc、cells)的Andr
  7. Android(安卓)数据保存到新建的一个excel
  8. Android(安卓)多媒体应用:视频播放之Vitam
  9. Android中Matrix用法实例分析
  10. [Android]使用浏览器直接打开PDF和Office