写在前面:
进入新公司,所在部门维护的产品是一个挺老的项目,前期由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();
}