Android官方早期中其实没有所谓的MVC框架,在我还是新手的时候,一个完整的Android项目其实是很混乱的,传统的MVC框架在Android上体现的不是很明显。最近在看了MVP框架自己动手写了以下发现MVP在Android中其实更像是传统的MVC。
MVP框架可以让UI界面和数据分离,我们的应用至少可以分为3层,这样使我们对这三层进行单独的单元测试,MVP模式可以让我们从Activity,Fragment等View角色中分离大部分代码,使得每个类型的代码量大幅度减少,职责单一,易于维护。
MVP中的三个角色
Presenter 交互中间人
Presenter主要作为沟通View和Model的桥梁,它从Model层检索数据后,返回给View层,使得View和Model之间没有耦合,也将业务逻辑从View角色中抽离出来
View-用户界面
View通常指的Activity,Fragment,或者某个View控件,它含有一个Presenter(也可以拥有多个)成员变量。通常View需要实现一个逻辑接口,将View上的操作通过转交给Presenter进行实现,最后,Presenter调用View逻辑接口将结果返回给View元素。
Model 数据的存储
Model角色主要是提供数据的存储功能,Presenter需要通过Model层存储,获取数据,Model就像一个数据仓库,Model更想封装了数据库Dao或者网络获取数据的角色。
MVP框架的封装
在使用MVP框架中,Presenter会持有Activity的强引用,在使用中经常会出现耗时操作,我们需要将Presenter中来绑定Activity Fragment的生命周期。我们采用的是弱引用和Activity fragment的生命周期来解决你这个问题,首先我们建立一个抽象Presenter
public abstract class BasePresenter<T>{
protected Reference<T> viewRef;
public void attachView(T view){
viewRef = new WeakReference<T>(view);
}
protected T getView(){
return viewRef.get();
}
public boolean isViewAttached(){
return viewRef != null && viewRef.get();
}
public void detachView(){
if(viewRef != null){
viewRef.clear();
viewRef = null;
}
}
}
BasePresenter 有4个方法,分别是View建立关联,解除关联,判断是否与View建立关联,获取View。View的类型通过泛型来传递,presenter持有一个View的弱引用。通常这个View的类型应该是一个实现了某个特定接口的Activity或者Fragment等类型。
public abstract class MVPBaseActivity<V,T extends BasePresenter<V>> extends Activity{
protected T presenter;
protected void onCreate(Bundle saveInstanceState){
super.onCreate();
presenter = createPresenter();
presenter.attachView((V)this);
}
protected void onDestroy(){
super.onDestory();
presenter.detachView();
}
protected abstract T createPresenter();
}
MVPBaseActivity 里面有两个泛型类型,一个是View接口类型,第二个是Presenter的具体类型。通过泛型参数,将一些通用的逻辑抽象到MVPBaseActivity里面,比如我们在抽象类中将Presenter 与View的逻辑直接完成,在子类继承父类的时候只需要实现抽象方法createPresenter即可完成绑定,调用父类的super.onCreate() 完成绑定,调用父类的super.onDestory()则会解除绑定。
通过继承MVPBaseActivity,实现抽象方法来完成MVP框架,代码如下有删减。
/**
* A login screen that offers login via email/password.
*/
public class LoginActivity extends MVPBaseActivity<ILoginView, LoginPresenter> implements ILoginView, View.OnClickListener {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
initListener();
initToolBar();
}
@Override
protected LoginPresenter createPresenter() {
return new LoginPresenter(this);
}
@Override
public void loginFail() {
showLoading(false);
Toast.makeText(this, "loginFail", Toast.LENGTH_SHORT).show();
}
@Override
public void loginSuccess(User user) {
showLoading(false);
Toast.makeText(this, "loginSuccess", Toast.LENGTH_SHORT).show();
setData(user);
}
}