欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android 浅谈MVP模式 一

程序员文章站 2022-06-08 22:24:56
...

一直想记录下最近学习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实现逻辑操作
 * <p>
 * View: 对于View层也是视图层,在View层中只负责对数据的展示,提供友好的界面与用户进行交互。
 * 在Android开发中通常将Activity或者Fragment作为View层。View与UI相关的
 * <p>
 * Model: 对于Model层也是数据层。它区别于MVC架构中的Model,在这里不仅仅只是数据模型。
 * 在MVP架构中Model它负责对数据的存取操作,例如对数据库的读写,网络的数据的请求等。
 * <p>
 * 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<User>() {
            //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模式 一

相关标签: MVP模式