简单的Android中MVP模式的应用

最近感觉自己的代码耦合性太高,打算重构一下自己代码的时候,于是花了两天的时间研究了一下MVP模式在Android中的应用。这里特地的记录一下所学。


什么叫做MVP模式?MVP模式的原理?这些这里推荐一片博文:http://www.jianshu.com/p/9a6845b26856写的很好,同时里面也记录了一些实现MVP模式的其他思路。


因为在Android中,我自己编程大多数使用的是Model-View模式,就是在Activity以及Fragment的生命周期中实现自己的功能,所以对于我们来说,Activity以及Fragment更多的承载了在传统MVC模式钟View以及Controller的功能。

而在Android开发中使用MVP模式,一种是将Activity作为View,自己创建Presenter来剥离逻辑以及功能。Presenter实现功能,View提供UI变化。


另外一种就是将Activity作为Presenter,具体实现思路有几种在 http://www.jianshu.com/p/9a6845b26856中有介绍。


除了MVP模式,Android开发中听说最近流行的是MVVM模式,后续如果有时间会研究一下!


Google官方也提供了MVP模式的Demo供大家学习,源码地址为:https://github.com/googlesamples/android-architecture ,其中的主要思路也是将Fragment作为View,同时书写Presenter。

这里借鉴Google思路,我尝试将自己目前进行的公司的项目中的登录模块改造为MVP模式,只不过是以Activity作为View。关于Google的Demo详细分析见:http://blog.youkuaiyun.com/u011459799/article/details/51360882"

首先,创建基本的View与Presenter,这里参考Google的Demo,如下:

public interface BasePresenter { 
//使用于Activity OnResume,用于恢复现场 
<span style="white-space:pre">	</span>void start(); 
} 
public interface BaseView<T> { 
//用于传递给View Presenter来操作(这么设计是有时候把Fragment作为View时)
<span style="white-space:pre">	</span>void setPresenter(T presenter); 
}

 

这里的BaseView中的setPresenter函数实际上是为了关联View和Presenter,因为在Google的Demo中,Presenter是在Activity中声明,然后Fragment作为View直接在Activty中直接设置了Presenter,在自己的例子中并不需要。

接下来,然后创建View以及Presenter实际接口,View提供UI变化接口,Presenter提供对View的操作以及功能的具体实现,如下:

public class LoginContract {

    interface View extends BaseView<Presenter> {
        /**
         * 显示Loading对话框
         */
        void showLoading();

        void dismissLoading();

        /**
         * 设置密码
         * @param password
         */
        void setPassword(String password);

        /**
         * 设置用户名
         * @param userName
         */
        void setUserName(String userName);

        /**
         * 设置用户名Edit的光标位置
         * @param index
         */
        void setUserNameSelection(int index);

        void setPasswordSelection(int index);

        String getUserName();

        String getPassword();

        RemoteDealEnsurenPopupWindow getThirdEnsureWindow();

        void setThirdEnsureWindow(RemoteDealEnsurenPopupWindow thirdEnsureWindow);

        /**
         * 显示第三方登录授权结果对话框
         */
        void showThirdEnsureWindow();

        void dismissThirdEnsureWindow();
    }

    interface Presenter extends BasePresenter {
        /**
         * 利用用户名登录
         */
        void userNameLogin();

        /**
         * qq第三方登录
         */
        void qqLogin();

        void wxLogin();

        void sinaLogin();

        /**
         * 忘记密码
         */
        void forgetPassword();

        /**
         * 注册新用户
         */
        void register();

        /**
         * 初始化UserName以及Password(账户密码存储)
         */
        void initLoginInfo();

        /**
         * 配置友盟第三方登录
         */
        void initUmengLogin();

        void umengAuthActivityResult(int requestCode, int resultCode, Intent data);
    }
}


如上完成接口的定义,然后在就是对Presenter以及View接口的具体实现。

Presenter实现:

public class LoginPresenter implements LoginContract.Presenter {

    /**
     * persenter初始化就是获取到View来操作View <br>
     * 同时将presenter传递给View<br>
     * 建立presenter与View的联系<br>
     *
     * @param rootView
     */
    public LoginPresenter(LoginContract.View rootView) {
        //获取View
        if (rootView instanceof LoginActivity)
            mRootView = (LoginActivity) rootView;
        //关联View和Presenter
        mRootView.setPresenter(this);
    }

    /**
     * 用户名密码输入
     */
    @Override
    public void userNameLogin() {
这里在Presenter的构造函数中获取到View,并且给View设置Presenter(本例中其实没必要)

接下来是View的实现,基本上是在Activity中完成简单UI操作封装,如下:

package cn.com.egova.securities_police.ui.Login;

import android.content.Intent;
import android.os.Bundle;
import android.text.InputType;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import cn.com.egova.securities_police.R;
import cn.com.egova.securities_police.ui.BaseActivity;
import cn.com.egova.securities_police.ui.widget.CustomImageEditText;
import cn.com.egova.securities_police.ui.widget.ProgressDialog;
import cn.com.egova.securities_police.ui.widget.RemoteDealEnsurenPopupWindow;

public class LoginActivity extends BaseActivity implements View.OnClickListener, LoginContract.View {
    public static final String TAG = "LoginActivity";
    //UI
    private TextView mRegisterText;
    private TextView mPasswordForgetText;
    private Button mLoginBtn;
    private CustomImageEditText mPhoneNoEdit;
    private CustomImageEditText mPasswordEdit;
    private ProgressDialog mProgressDialog;
    private ImageView mQqLoginImg;
    private ImageView mWcLoginImg;
    private ImageView mAilpayLoginImg;
    private View mContianer;
    private RemoteDealEnsurenPopupWindow mThirdLoginEnsureWindow;

    //MVP Presenter
    private LoginContract.Presenter mLoginPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_login);
        //申明Presenter
        new LoginPresenter(this);
        //申明View
        initView();
        //初始化Umeng登录
        mLoginPresenter.initUmengLogin();
    }

    public void initView() {
        //控件优化
        mContianer = findViewById(R.id.login_activity_container);
        mRegisterText = (TextView) findViewById(R.id.login_activity_register_text);
        mRegisterText.setOnClickListener(this);
        mPasswordForgetText = (TextView) findViewById(R.id.login_activity_password_forget_text);
        mPasswordForgetText.setOnClickListener(this);
        mLoginBtn = (Button) findViewById(R.id.login_activity_login_btn);
        mLoginBtn.setOnClickListener(this);
        mPhoneNoEdit = (CustomImageEditText) findViewById(R.id.login_activity_phone_number_edit);
        mPasswordEdit = (CustomImageEditText) findViewById(R.id.login_activity_password_edit);
        mPhoneNoEdit.getEditText().setInputType(InputType.TYPE_CLASS_TEXT);
        mPasswordEdit.getEditText().setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
        mPhoneNoEdit.getIcon().setImageResource(R.mipmap.edit_icon_phone_num);
        mPasswordEdit.getIcon().setImageResource(R.mipmap.edit_icon_password);
        mProgressDialog = new ProgressDialog(this);

        //第三方登录
        mQqLoginImg = (ImageView) findViewById(R.id.login_activity_qq_icon);
        mWcLoginImg = (ImageView) findViewById(R.id.login_activity_wc_icon);
        mAilpayLoginImg = (ImageView) findViewById(R.id.login_activity_alipay_icon);
        mQqLoginImg.setOnClickListener(this);
        mWcLoginImg.setOnClickListener(this);
        mAilpayLoginImg.setOnClickListener(this);

        //初始化登录信息
        mLoginPresenter.initLoginInfo();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.login_activity_register_text:
                mLoginPresenter.register();
                break;
            case R.id.login_activity_password_forget_text:
                mLoginPresenter.forgetPassword();
                break;
            case R.id.login_activity_login_btn:
                mLoginPresenter.userNameLogin();
                break;
            case R.id.login_activity_qq_icon:
                //友盟QQ登陆
                mLoginPresenter.qqLogin();
                break;
            case R.id.login_activity_wc_icon:
                //跳转到微信授权界面
                mLoginPresenter.wxLogin();
                break;
            case R.id.login_activity_alipay_icon:
                //新浪微博登陆
                mLoginPresenter.sinaLogin();
                break;
            default:
                break;
        }
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        //友盟QQ授权登陆
        mLoginPresenter.umengAuthActivityResult(requestCode, resultCode, data);
    }

    @Override
    public void onResume() {
        super.onResume();
        mLoginPresenter.start();
    }

    @Override
    public void showLoading() {
        mProgressDialog.show();
    }

    @Override
    public void dismissLoading() {
        mProgressDialog.dismiss();
    }

    @Override
    public void setPassword(String password) {
        mPasswordEdit.getEditText().setText(password);
    }

    @Override
    public void setUserName(String userName) {
        mPhoneNoEdit.getEditText().setText(userName);
    }

    @Override
    public void setUserNameSelection(int index) {
        mPhoneNoEdit.getEditText().setSelection(index);
    }

    @Override
    public void setPasswordSelection(int index) {
        mPasswordEdit.getEditText().setSelection(index);
    }

    @Override
    public String getUserName() {
        return String.valueOf(mPhoneNoEdit.getEditText().getText());
    }

    @Override
    public String getPassword() {
        return String.valueOf(mPasswordEdit.getEditText().getText());
    }

    @Override
    public RemoteDealEnsurenPopupWindow getThirdEnsureWindow() {
        return mThirdLoginEnsureWindow;
    }

    @Override
    public void setThirdEnsureWindow(RemoteDealEnsurenPopupWindow thirdEnsureWindow) {
        mThirdLoginEnsureWindow = thirdEnsureWindow;
    }

    @Override
    public void showThirdEnsureWindow() {
        if (mThirdLoginEnsureWindow != null) {
            mThirdLoginEnsureWindow.showPopupWindow(mContianer);
        }
    }

    @Override
    public void dismissThirdEnsureWindow() {
        if (mThirdLoginEnsureWindow != null) {
            mThirdLoginEnsureWindow.dismiss();
        }
    }

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

}

这样,基本上就将所有功能实现抽离在Presenter中了,比起原来臃肿的Activity,现在看起来也舒服多了。

目前,这也是简单的研究了一下MVP模式的使用,想要大范围的使用肯定还会遇到一些问题,后续会专门进行讲解。

附上例子的部分代码 :

DiskyZhs/Android_Mvp_Model_Demo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值