MVP的使用与Activity的封装

写在前面:
  进入新公司,所在部门维护的产品是一个挺老的项目,前期由eclipse开发,现在转为AS。许多代码采用MVC模式,梳理起来挺费劲。虽然也有某些方面使用MVP处理,但是封装的并不太好,由此萌生自己写一个MVP供自己使用的想法。
  下面开始我的mvp封装之路。


MVP

1.什么是MVP

MVP 即 Model-View-Presenter,
    M:业务逻辑和实体模型
    V:对应Activity,负责view的绘制和用户交互
    P:负责连接 V 与 M

2.MVP在安卓中使用的好处

mvp是一种设计模式思想,根据不同的业务场景有不同的封装形式。

应用到安卓中:
  1.它减少了Activity的职责,简化了Activity的代码。
  2.让Activity专注于view的处理与用户的交互。而具体的逻辑与数据的处理,交给Presenter处理。
  3.使我们代码的耦合性更低,模块职责区分明显。
  4.代码更灵活、健壮。

3.我的项目中的MVP使用。

V的顶层接口View,用户连接Activity与Presenter。

public interface View {
}

IPresenter,记录Presenter生命周期

public interface IPresenter {
    void onCreate();
    void onStart();
    void onPause();
    void onStop();
    void onDestroy();
}

Presenter,利用泛型,使之与View产生关系。


public class Presenter<V extends View> implements IPresenter {

    private V view;

    /**
     * 绑定presenter和view
     *
     * @param view
     */
    public void attachView(V view) {
        this.view = view;
    }

    /**
     * 获取当前界面
     */
    protected V getView() {
        return view;
    }

    @Override
    public void onCreate() {
        if (useEventBus() && !EventBus.getDefault().isRegistered(this))
            EventBus.getDefault().register(this);
    }

    @Override
    public void onStart() {
        // Unused
    }

    @Override
    public void onPause() {
        // Unused
    }

    @Override
    public void onStop() {
        // Unused
    }

    /**
     * 解绑界面和presenter
     */
    @Override
    public void onDestroy() {
        if (useEventBus())//如果要使用eventbus请将此方法返回true
            EventBus.getDefault().unregister(this);
        if (view != null) {
            view = null;
        }
    }

    /**
     * 是否使用eventBus,默认为不使用(false),
     */
    protected boolean useEventBus() {
        return false;
    }
}

抽取通用的BaseActivity

1.抽取思想

就如上面定义Prestener一样,因为P层主要是来处理业务逻辑,比如可能会接收一些EventBus事件,所以在Prestener中定义了一个方法

    /**
     * 是否使用eventBus,默认为不使用(false),
     */
    protected boolean useEventBus() {
        return false;
    }

当P在onCreate()的时候,我们进行注册:

if (useEventBus() && !EventBus.getDefault().isRegistered(this))
    EventBus.getDefault().register(this);

同理,在P销毁的时候,进行取消注册:

if (useEventBus())
    EventBus.getDefault().unregister(this);

这样当我们需要使用EventBus的时候,只需在P中重写useEventBus()方法就可以。

对于Activity,我们同样也可以做类似的处理。

1.Activity的进出场动画

    /**
     * 几种页面切换动画的枚举类
     */
    public enum TransitionMode {
        FADE , LEFT2RIGHT
    }

在Activity启动和销毁的时候分别执行切换动画的逻辑

// 启动自定义进出动画
if (isCustomPendingTransition()) {
    switch (getCustomPendingTransitionType()) {
        case FADE:
            overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
            break;
        case LEFT2RIGHT:
            overridePendingTransition(R.anim.left_in, R.anim.rig);
            break;
    }
}

2.活动跳转相关封装

Activity进行跳转抽取到Base类中

/***************************************** 活动跳转相关 *****************************************/

    /**
     * 跳转另一个活动
     *
     * @param clazz
     */
    protected void go(Class<?> clazz) {
        Intent intent = new Intent(this, clazz);
        startActivity(intent);
    }

    /**
     * 跳转另一个活动并传递参数
     *
     * @param clazz
     * @param bundle
     */
    protected void go(Class<?> clazz, Bundle bundle) {
        Intent intent = new Intent(this, clazz);
        if (null != bundle) {
            intent.putExtras(bundle);
        }
        startActivity(intent);
    }

    /**
     * 跳转另一个活动并结束当前
     *
     * @param clazz
     */
    protected void goThenKill(Class<?> clazz) {
        Intent intent = new Intent(this, clazz);
        startActivity(intent);
        finish();
    }

    /**
     * 跳转另一个活动并结束,并传递参数
     *
     * @param clazz
     * @param bundle
     */
    protected void goThenKill(Class<?> clazz, Bundle bundle) {
        Intent intent = new Intent(this, clazz);
        if (null != bundle) {
            intent.putExtras(bundle);
        }
        startActivity(intent);
        finish();
    }

    /**
     * 开始一个活动,并等待返回结果
     *
     * @param clazz
     * @param requestCode
     */
    protected void goForResult(Class<?> clazz, int requestCode) {
        Intent intent = new Intent(this, clazz);
        startActivityForResult(intent, requestCode);
    }

    /**
     * 开始一个活动,并等待返回结果,并传递参数
     *
     * @param clazz
     * @param requestCode
     * @param bundle
     */
    protected void goForResult(Class<?> clazz, int requestCode, Bundle bundle) {
        Intent intent = new Intent(this, clazz);
        if (null != bundle) {
            intent.putExtras(bundle);
        }
        startActivityForResult(intent, requestCode);
    }

    /***************************************** 活动跳转相关 *****************************************/

3.软键盘收缩管理

   @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            android.view.View v = getCurrentFocus();
            if (isShouldHideInput(v, ev)) {

                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                if (imm != null) {
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                }
            }
            return super.dispatchTouchEvent(ev);
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

    private boolean isShouldHideInput(android.view.View v, MotionEvent event) {
        if (v != null && (v instanceof EditText)) {
            int[] location = {0, 0};
            v.getLocationOnScreen(location);
            int left = location[0];
            int top = location[1];

            if (event.getX() < left || (event.getX() > left + v.getWidth())
                    || event.getY() < top || (event.getY() > top + v.getHeight())) {
                return true;
            } else {
                return false;
            }
        }
        return false;
    }

4.定义抽象方法,让子类复写。
在BaseActivity的onCreate方法中

    setContentView(setLayoutId());
    initView();
    initEvents();

类中定义如下抽象方法,让子类重写

    /**
     * 设置layout id
     */
    protected abstract int setLayoutId();

    /**
     * 初始化所有布局
     */
    protected abstract void initView();

    /**
     * 初始化所有event事件
     */
    protected abstract void initEvents();

这样一个基本都Activity就抽取好了。以后可以根据具体的业务场景去丰富它。

完整的BaseActivity如下:


public abstract class BaseActivity<P extends Presenter> extends FragmentActivity implements View {
    protected P mPresenter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
//        MyApplication.getInstance().addActivity(this);

        // 启动自定义进出动画
        if (isCustomPendingTransition()) {
            switch (getCustomPendingTransitionType()) {
                case FADE:
//                    overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
                    break;
                case LEFT2RIGHT:
//                    overridePendingTransition(R.anim.left_in, R.anim.rig);

                    break;
            }
        }
        super.onCreate(savedInstanceState);

        mPresenter = createPresenter();
        mPresenter.onCreate();
        mPresenter.attachView(this);

        setContentView(setLayoutId());
        initView();
        initEvents();
    }

    @Override
    public void finish() {
        super.finish();

        if (isCustomPendingTransition()) {
            switch (getCustomPendingTransitionType()) {
                case FADE:
//                    overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
                    break;
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
//        MyApplication.getInstance().removeActivity(this);
        //解绑presenter
        mPresenter.onDestroy();
        mPresenter = null;
    }

    protected abstract P createPresenter();

    /***************************************** 设置启动销毁动画 *****************************************/

    /**
     * 几种页面切换动画的枚举类
     */
    public enum TransitionMode {
        FADE , LEFT2RIGHT
    }

    /**
     * @return true--自定义页面的切换动画   false--不自定义
     */
    protected boolean isCustomPendingTransition() {
        return false;
    }

    /**
     * @return 返回自定义的动画切换方式
     */
    protected TransitionMode getCustomPendingTransitionType() {
        return TransitionMode.FADE;
    }
    /***************************************** 设置启动销毁动画 *****************************************/


    /***************************************** 活动跳转相关 *****************************************/

    /**
     * 跳转另一个活动
     *
     * @param clazz
     */
    protected void go(Class<?> clazz) {
        Intent intent = new Intent(this, clazz);
        startActivity(intent);
    }

    /**
     * 跳转另一个活动并传递参数
     *
     * @param clazz
     * @param bundle
     */
    protected void go(Class<?> clazz, Bundle bundle) {
        Intent intent = new Intent(this, clazz);
        if (null != bundle) {
            intent.putExtras(bundle);
        }
        startActivity(intent);
    }

    /**
     * 跳转另一个活动并结束当前
     *
     * @param clazz
     */
    protected void goThenKill(Class<?> clazz) {
        Intent intent = new Intent(this, clazz);
        startActivity(intent);
        finish();
    }

    /**
     * 跳转另一个活动并结束,并传递参数
     *
     * @param clazz
     * @param bundle
     */
    protected void goThenKill(Class<?> clazz, Bundle bundle) {
        Intent intent = new Intent(this, clazz);
        if (null != bundle) {
            intent.putExtras(bundle);
        }
        startActivity(intent);
        finish();
    }

    /**
     * 开始一个活动,并等待返回结果
     *
     * @param clazz
     * @param requestCode
     */
    protected void goForResult(Class<?> clazz, int requestCode) {
        Intent intent = new Intent(this, clazz);
        startActivityForResult(intent, requestCode);
    }

    /**
     * 开始一个活动,并等待返回结果,并传递参数
     *
     * @param clazz
     * @param requestCode
     * @param bundle
     */
    protected void goForResult(Class<?> clazz, int requestCode, Bundle bundle) {
        Intent intent = new Intent(this, clazz);
        if (null != bundle) {
            intent.putExtras(bundle);
        }
        startActivityForResult(intent, requestCode);
    }

    /***************************************** 活动跳转相关 *****************************************/


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            android.view.View v = getCurrentFocus();
            if (isShouldHideInput(v, ev)) {

                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                if (imm != null) {
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                }
            }
            return super.dispatchTouchEvent(ev);
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

    private boolean isShouldHideInput(android.view.View v, MotionEvent event) {
        if (v != null && (v instanceof EditText)) {
            int[] location = {0, 0};
            v.getLocationOnScreen(location);
            int left = location[0];
            int top = location[1];

            if (event.getX() < left || (event.getX() > left + v.getWidth())
                    || event.getY() < top || (event.getY() > top + v.getHeight())) {
                return true;
            } else {
                return false;
            }
        }
        return false;
    }

    /**
     * 设置layout id
     */
    protected abstract int setLayoutId();

    /**
     * 初始化所有布局
     */
    protected abstract void initView();

    /**
     * 初始化所有event事件
     */
    protected abstract void initEvents();

}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值