關於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
- 泛型和模板設計模式
等。