Android 浅谈MVP模式 一

一直想记录下最近学习MVP模式的一些心得,又怕写的太渣,没办法,先写写然后及时更新。 我会粘贴一些代码,对于MVP模式的理解会在代码中详细注释

例一:闪屏界面判断是否已经登录

/**
 * MVP 思想 : MVP中Activity/fragment属于View ,因此要有一个View的接口,然后Activity/fragment实现View接口
 * P 中创建业务层 Presenter中定义功能,实现类PresenterImpl中操作功能/逻辑
 * 在Activity/fragment中 声明初始化 p,只能new SplashPresenter 的实现类,不能new SplashPresenter接口,
 * P 中一般要回调Activity/fragment 中的方法,所以要传入“this”,(PresenterImpl 是 Presenter的实现类)
 * 在 p 中生成构造函数,xxView(因为是面向接口,生成的是xxView构造函数,而不是xxActivity构造函数)
 * Activity/fragment 中的回调方法一般都添加到View中去,而真正调用的是在PresenterImpl中,在Activity/fragment实现逻辑操作
 * 

* View: 对于View层也是视图层,在View层中只负责对数据的展示,提供友好的界面与用户进行交互。 * 在Android开发中通常将Activity或者Fragment作为View层。View与UI相关的 *

* Model: 对于Model层也是数据层。它区别于MVC架构中的Model,在这里不仅仅只是数据模型。 * 在MVP架构中Model它负责对数据的存取操作,例如对数据库的读写,网络的数据的请求等。 *

* Presenter:对于Presenter层他是连接View层与Model层的桥梁并对业务逻辑进行处理。 * 在MVP架构中Model与View无法直接进行交互。所以在Presenter层它会从Model层获得所需要的数据, * 进行一些适当的处理后交由View层进行显示。这样通过Presenter将View与Model进行隔离, * 使得View和Model之间不存在耦合,同时也将业务逻辑从View中抽离。 */ //View层 public class SplashActivity extends BaseActivity implements SplashView { private static final long DURATION = 2000; private SplashPresenter mSplashPresenter; @InjectView(R.id.iv_splash) ImageView mIvSplash; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash); ButterKnife.inject(this); //TODO /** * 在Activity/fragment中 声明初始化 p ,只能new SplashPresenter 的实现类,不能new SplashPresenter接口 */ mSplashPresenter = new SplashPresenterImpl(this); /** * 1. 判断是否已经登录了 P层 * 2. 如果登录了,直接进入MainActivity view层 * 3. 否则闪屏2秒后(添加渐变动画),进入LoginActivity view层 */ mSplashPresenter.checkLogined(); } //Activity/fragment 中的回调方法一般都添加到View中去,而真正调用的是在PresenterImpl中,在Activity/fragment实现逻辑操作 @Override public void onCheckedLogin(boolean isLogined) { if (isLogined) { //跳转Activity类抽取 MainActivity.class :要调转的类 ,true :跳转之后finish掉 startActivity(MainActivity.class, true); } else { // 否则闪屏2秒后(添加渐变动画),进入LoginActivity ObjectAnimator alpha = ObjectAnimator.ofFloat(mIvSplash, "alpha", 0, 1).setDuration(DURATION); alpha.start(); //动画执行完再跳转,直接回调监听,不需要handler alpha.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); startActivity(LoginActivity.class, true); } }); } } }

/**
 * 作者: itheima
 * 时间:2016-10-15 10:50
 * 网址:http://www.itheima.com
 * 生成构造函数,xxView(因为是面向接口,生成的是xxView构造函数,而不是xxActivity构造函数)
 */

public interface SplashView {

    void onCheckedLogin(boolean isLogined);
}

P层:

/**
 * 作者: itheima
 * 时间:2016-10-15 10:50
 * 网址:http://www.itheima.com
 * P 中创建业务层 Presenter中定义功能,实现类PresenterImpl中操作功能/逻辑
 */
//创建业务层 Presenter中定义功能
public interface SplashPresenter {
    void checkLogined();
}
/**
 * 作者: itheima
 * 时间:2016-10-15 10:51
 * 网址:http://www.itheima.com
 * P 中创建业务层 Presenter中定义功能,实现类PresenterImpl中操作功能/逻辑
 */

public class SplashPresenterImpl implements SplashPresenter {

    //在 p 中生成构造函数,xxView(因为是面向接口,生成的是xxView构造函数,而不是xxActivity构造函数)
    private SplashView mSplashView;

    public SplashPresenterImpl(SplashView splashView) {
        mSplashView = splashView;
    }

    //实现类PresenterImpl中操作功能/逻辑
    @Override
    public void checkLogined() {
        if (EMClient.getInstance().isLoggedInBefore() && EMClient.getInstance().isConnected()) {
            //已经登录过了
            mSplashView.onCheckedLogin(true);
        } else {
            //还未登录
            mSplashView.onCheckedLogin(false);
        }

    }
}

例二:用户登录是否成功,保存账户和密码

View层:

public class LoginActivity extends BaseActivity implements TextView.OnEditorActionListener ,LoginView{

    private static final int REQUEST_SDCARD = 1;

    @InjectView(R.id.et_username)
    EditText mEtUsername;
    @InjectView(R.id.til_username)
    TextInputLayout mTilUsername;
    @InjectView(R.id.et_pwd)
    EditText mEtPwd;
    @InjectView(R.id.til_pwd)
    TextInputLayout mTilPwd;
    @InjectView(R.id.btn_login)
    Button mBtnLogin;
    @InjectView(R.id.tv_newuser)
    TextView mTvNewuser;

    private LoginPresenter mLoginPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Window window = getWindow();
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                    | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setStatusBarColor(Color.TRANSPARENT);
//            window.setNavigationBarColor(Color.TRANSPARENT);
        }
        setContentView(R.layout.activity_login);
        ButterKnife.inject(this);
        /**
         * 数据的回显
         */
        mEtUsername.setText(getUserName());
        mEtPwd.setText(getPwd());
        mEtPwd.setOnEditorActionListener(this);

        mLoginPresenter = new LoginPresenterImpl(this);
    }

    /**
     * 当再次startActivity的时候,接收新的Intent对象
     * 调用的前提是该启动模式是singleTask,或者singleTop但是他得在最上面才有效
     * @param intent
     */
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        mEtUsername.setText(getUserName());
        mEtPwd.setText(getPwd());
    }

    @OnClick({R.id.btn_login, R.id.tv_newuser})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_login:
                login();
                break;
            case R.id.tv_newuser:
            startActivity(RegistActivity.class,false);

                break;
        }
    }

    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (v.getId()==R.id.et_pwd){
            if (actionId== EditorInfo.IME_ACTION_DONE){
                login();
            }
        }
        return false;
    }

    private void login() {
        String username = mEtUsername.getText().toString().trim();
        String pwd = mEtPwd.getText().toString().trim();

        if (!StringUtils.checkUsername(username)){
            mTilUsername.setErrorEnabled(true);
            mTilUsername.setError("用户名不合法");

            mEtUsername.requestFocus(View.FOCUS_RIGHT);

            return;
        }else {
            mTilUsername.setErrorEnabled(false);
        }
        if (!StringUtils.checkPwd(pwd)){
            mTilPwd.setErrorEnabled(true);
            mTilPwd.setError("密码不合法");

            mEtPwd.requestFocus(View.FOCUS_RIGHT);
            return;
        }else{
            mTilPwd.setErrorEnabled(false);
        }
        /**
         * 1. 动态申请权限
         */
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PermissionChecker.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},REQUEST_SDCARD);
            return;
        }

        showDialog("正在玩命登录中...");

        mLoginPresenter.login(username,pwd);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode==REQUEST_SDCARD){
            if (grantResults[0]==PermissionChecker.PERMISSION_GRANTED){
                //被授权了
                login();
            }else{
                showToast("没有给予该应用权限,不让你用了");
            }
        }
    }

    @Override
    public void onLogin(String username, String pwd, boolean success, String msg) {
        hideDialog();
        if (success){
            /**
             * 1.保存用户
             * 2. 跳转到主界面
             */
            saveUser(username, pwd);
            startActivity(MainActivity.class,true);
        }else {
            /**
             * 1.Toast
             */
            showToast("登录失败了:"+msg);
        }
    }
}
/**
 * 作者: itheima
 * 时间:2016-10-15 17:13
 * 网址:http://www.itheima.com
 */
public interface LoginView {
    void onLogin(String username,String pwd,boolean success,String msg);
}

P层:P 中创建业务层 Presenter中定义功能,实现类PresenterImpl中操作功能/逻辑

/**
 * 作者: itheima
 * 时间:2016-10-15 17:13
 * 网址:http://www.itheima.com
 */
public interface LoginPresenter {
    void login(String username,String pwd);
}

 

/**
 * 作者: itheima
 * 时间:2016-10-15 17:14
 * 网址:http://www.itheima.com
 */
public class LoginPresenterImpl implements LoginPresenter {
    private LoginView mLoginView;

    public LoginPresenterImpl(LoginView loginView) {
        mLoginView = loginView;
    }

    @Override
    public void login(final String username, final String pwd) {

        //环信目前(3.5.x)的所有回调方法都是在子线程中回调的
        EMClient.getInstance().login(username, pwd, new CallBackListener() {
            @Override
            public void onMainSuccess() {
                mLoginView.onLogin(username,pwd,true,null);
            }

            @Override
            public void onMainError(int i, String s) {
                mLoginView.onLogin(username,pwd,false,s);
            }
        });
    }
}

例三:注册是否成功,成功保存账户密码进入登录页面,失败吐司

View层:

public class RegistActivity extends BaseActivity implements TextView.OnEditorActionListener, RegistView {

    @InjectView(R.id.et_username)
    EditText mEtUsername;
    @InjectView(R.id.til_username)
    TextInputLayout mTilUsername;
    @InjectView(R.id.et_pwd)
    EditText mEtPwd;
    @InjectView(R.id.til_pwd)
    TextInputLayout mTilPwd;
    @InjectView(R.id.btn_regist)
    Button mBtnRegist;

    private RegistPresenter mRegistPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Window window = getWindow();
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                    | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setStatusBarColor(Color.TRANSPARENT);
//            window.setNavigationBarColor(Color.TRANSPARENT);
        }


        setContentView(R.layout.activity_regist);
        ButterKnife.inject(this);
        mRegistPresenter = new RegistPresenterImpl(this);
        //给UI绑定事件
        mEtPwd.setOnEditorActionListener(this);
    }

    @OnClick(R.id.btn_regist)
    public void onClick() {
        regist();
    }

    private void regist() {
        String username = mEtUsername.getText().toString().trim();
        String pwd = mEtPwd.getText().toString().trim();

        if (!StringUtils.checkUsername(username)){
            mTilUsername.setErrorEnabled(true);
            mTilUsername.setError("用户名不合法");

            mEtUsername.requestFocus(View.FOCUS_RIGHT);

            return;
        }else {
            mTilUsername.setErrorEnabled(false);
        }
        if (!StringUtils.checkPwd(pwd)){
            mTilPwd.setErrorEnabled(true);
            mTilPwd.setError("密码不合法");

            mEtPwd.requestFocus(View.FOCUS_RIGHT);
            return;
        }else{
            mTilPwd.setErrorEnabled(false);
        }
        showDialog("正在注册...");
        mRegistPresenter.regist(username,pwd);
    }
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (v.getId() == R.id.et_pwd) {
            if (actionId == EditorInfo.IME_ACTION_DONE) {
                regist();
                return true;
            }
        }
        return false;
    }

    @Override
    public void onRegist(String username, String pwd, boolean isSuccess, String msg) {
        hideDialog();
        if (isSuccess){
            /**
             * 将注册成功的数据保存到本地
             * 跳转到登录界面
             */
            saveUser(username, pwd);

            startActivity(LoginActivity.class,true);
        }else {
            /**
             * 弹吐司,告诉用户失败了
             */
            showToast("注册失败:"+msg);
        }
    }
}
/**
 * 作者: itheima
 * 时间:2016-10-15 11:49
 * 网址:http://www.itheima.com
 */

public interface RegistView {

    void onRegist(String username,String pwd,boolean isSuccess,String msg);
}

P层:

/**
 * 作者: itheima
 * 时间:2016-10-15 11:47
 * 网址:http://www.itheima.com
 */

public interface RegistPresenter {
    void regist(String username,String pwd);
}
/**
 * 作者: itheima
 * 时间:2016-10-15 11:48
 * 网址:http://www.itheima.com
 */

public class RegistPresenterImpl implements RegistPresenter {

    private RegistView mRegistView;

    public RegistPresenterImpl(RegistView registView) {
        mRegistView = registView;
    }

    @Override
    public void regist(final String username, final String pwd) {
        /**
         * 1. 先注册Bmob云数据库
         * 2. 如果Bmob成功了再去注册环信平台
         * 3. 如果Bmob成功了,环信失败了,则再去把Bmob上的数据给删除掉
         */
        User user = new User();
        user.setPassword(pwd);
        user.setUsername(username);

        user.signUp(new SaveListener() {
            //Bmob中的回调方法都是在主线程中被调用的
            @Override
            public void done(final User user, BmobException e) {
                if (e==null){
                    //new Thread。。。new线程是一个很耗时的操作,不如牺牲空间换时间
                    //提前把线程创建好,不用每次都要new线程

                    //成功了再去注册环信平台
                    ThreadUtils.runOnSubThread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                EMClient.getInstance().createAccount(username, pwd);
                                //环信注册成功 主线程中回调
                                ThreadUtils.runOnMainThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        mRegistView.onRegist(username,pwd,true,null);
                                    }
                                });
                            } catch (final HyphenateException e1) {
                                e1.printStackTrace();
                                //将Bmob上注册的user给删除掉
                                user.delete();
                                //环信注册失败了
                                ThreadUtils.runOnMainThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        mRegistView.onRegist(username,pwd,false,e1.toString());
                                    }
                                });
                            }
                        }
                    });
                }else {
                    //失败了,将结果告诉Activity
                    mRegistView.onRegist(username,pwd,false,e.getMessage());
                }
            }
        });

    }
}

另外我也参考了一些资料:http://chuansong.me/n/632293551521

http://chuansong.me/n/2271649851831

希望对你有所帮助

你可能感兴趣的:(Android 浅谈MVP模式 一)