关于MVC,MVP,MVVM,有很多人写了区别,比如这篇。
这里只是分析大多数人使用的MVP框架 mosby MVP,代码请点击。
首先再来回顾一下MVP的整体概念,View不直接和Model打交道(区别于MVC)View和Presenter之间互相调用,Model只和Presenter交互,一般由Presenter这方调用。
mosby MVP框架代码相关几个部分
View层:
- MvpActivity(实际控制)
- MvpView (接口)
- ActivityMvpDelegateImpl (用于处理Presenter的新建)
Presenter层
- MvpPresenter
- MVpBasePresenter
部分重要代码
MvpView.java是空接口为的是外部使用View接口
MvpActivity.java
public abstract class MvpActivity<V extends MvpView, P extends MvpPresenter<V>> extends AppCompatActivity implements MvpView, com.hannesdorfmann.mosby3.mvp.delegate.MvpDelegateCallback<V,P> { protected ActivityMvpDelegate mvpDelegate; protected P presenter; protected boolean retainInstance; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getMvpDelegate().onCreate(savedInstanceState); }
@NonNull protected ActivityMvpDelegate<V, P> getMvpDelegate() { if (mvpDelegate == null) { mvpDelegate = new ActivityMvpDelegateImpl(this, this, true); } return mvpDelegate; } @NonNull @Override public P getPresenter() { return presenter; } @Override public void setPresenter(@NonNull P presenter) { this.presenter = presenter; } @NonNull @Override public V getMvpView() { return (V) this; } }
MvpActivity这里作为 ActivityMvpDelegateImpl的Callbcack设置Presenter和View(Activity本身)。MvpActivity里面存有Presenter的实例,则可以通过调用getPresenter实现View到Presenter的调用。
ActivityMvpDelegateImpl.java
@Override public void onCreate(Bundle bundle) { P presenter = null; if (bundle != null && keepPresenterInstance) { mosbyViewId = bundle.getString(KEY_MOSBY_VIEW_ID); if (DEBUG) { Log.d(DEBUG_TAG, "MosbyView ID = " + mosbyViewId + " for MvpView: " + delegateCallback.getMvpView()); } if (mosbyViewId != null && (presenter = PresenterManager.getPresenter(activity, mosbyViewId)) != null) { // // Presenter restored from cache // if (DEBUG) { Log.d(DEBUG_TAG, "Reused presenter " + presenter + " for view " + delegateCallback.getMvpView()); } } else { // // No presenter found in cache, most likely caused by process death // presenter = createViewIdAndCreatePresenter(); if (DEBUG) { Log.d(DEBUG_TAG, "No presenter found although view Id was here: " + mosbyViewId + ". Most likely this was caused by a process death. New Presenter created" + presenter + " for view " + getMvpView()); } } } else { // // Activity starting first time, so create a new presenter // presenter = createViewIdAndCreatePresenter(); if (DEBUG) { Log.d(DEBUG_TAG, "New presenter " + presenter + " for view " + getMvpView()); } } if (presenter == null) { throw new IllegalStateException( "Oops, Presenter is null. This seems to be a Mosby internal bug. Please report this issue here: https://github.com/sockeqwe/mosby/issues"); } delegateCallback.setPresenter(presenter); getPresenter().attachView(getMvpView()); if (DEBUG) { Log.d(DEBUG_TAG, "View" + getMvpView() + " attached to Presenter " + presenter); } }
private P createViewIdAndCreatePresenter() { P presenter = delegateCallback.createPresenter(); if (presenter == null) { throw new NullPointerException( "Presenter returned from createPresenter() is null. Activity is " + activity); } if (keepPresenterInstance) { mosbyViewId = UUID.randomUUID().toString(); PresenterManager.putPresenter(activity, mosbyViewId, presenter); } return presenter; }
MvpPresenter实例是在MvpActivity的代理ActivityMvpDelegateImpl中创建。并且将当前的View(即Activity实例)设置到了MvpPresenter里面用于回调。
MvpActivity与MvpPresenter与ActivityMvpDelegateImpl都是1:1:1的关系。
MvpBasePresenter.java
public interface ViewAction<V> { /** * This method will be invoked to run the action. Implement this method to interact with the view. * @param view The reference to the view. Not null. */ void run(@NonNull V view); } private WeakReference<V> viewRef; private boolean presenterDestroyed = false; @UiThread @Override public void attachView(V view) { viewRef = new WeakReference<V>(view); presenterDestroyed = false; }
protected final void ifViewAttached(boolean exceptionIfViewNotAttached, ViewAction<V> action) { final V view = viewRef == null ? null : viewRef.get(); if (view != null) { action.run(view); } else if (exceptionIfViewNotAttached) { throw new IllegalStateException( "No View attached to Presenter. Presenter destroyed = " + presenterDestroyed); }通过判断是否存在View是否存在来执行ViewAction的run方法来执行presenter到View的回调。
MVP框架启动Presenter生成和设置的序列图
继承MVP框架自己的实现
MyPresenter.java
public void getData(String data) { try { Thread.sleep(1000); } catch (Exception e){ } ifViewAttached(new ViewAction<MyView>() { @Override public void run(@NonNull MyView view) { view.showData(); } });
}
MyActivity.java
@NonNull @Override public MyPresenter createPresenter() { return new MyPresenter(); } public void getData(View view){ getPresenter().getData("data"); }
@Override public void showData(Contributor contributor) { topContributor.setText(contributor.toString()); dismissProgress(); }
View中调用Presenter向Model获取数据,然后Presenter再回调View(Acitivity)的ShowData方法。
另该MVP框架中使用到的模式有:
- 代理模式Delegate
- 泛型和模板设计模式
等。