看過mvp結構的人都知道,在官方版本的mvp里面有很多大量的接口定義,沒錯 就是接口,沒次都要寫大量的接口,時間久了會覺得很煩,這里簡化了一個mvp的標準寫法少了很多接口定義,至少我現在項目中正在這么使用,不過這個MVP目前還有一層沒有挖掘,那就是M層,不過在看了[架構向] 談Android中DTO -> VO的重要性文章以后,感覺可以用在現在的M層中,做DTO,這樣讓P層在拿到數據以后只專心處理邏輯,而不用判斷太多的數據校驗。
先來看看傳統的MVP的結構走向圖:
這次的簡化來源于經過實踐發現,大部分Presenter------>View的都只是鋪鋪數據,而本著一個View擁有一個Presenter的原則,所以簡化過后的結構走向還是原來的結構走向,只是少了一點接口而已,也算的上是對MVP的一種簡化的封裝。
首先我們先來看看BasePresenter類:
public abstract class BasePresenter<T extends BaseView> {
private WeakReference<T> weakReference;
public BasePresenter(T baseView) {
setView(baseView);
}
public T getView() {
return weakReference!=null?weakReference.get():null;
}
public void setView(T view) {
this.weakReference = new WeakReference<>(view);
}
public void recycle(){
if(weakReference!=null){
weakReference.clear();
weakReference=null;
}
}
}
所有的Presenter都需要繼承這個BasePresenter,更具結構類圖,此類中需要依賴一個視圖層的接口,因此在繼承此類的時候通過泛型看到需要傳入一個繼承自BaseView接口的接口。沒錯Presenter層在向View通信的時候任然是需要依靠接口來通信的,這里取消了Presneter和Model的接口依賴關。從大部分實踐上來看,感覺這兩曾的的依賴關系并不是很重要,所以取消掉了,當然也有可能是我還沒發現P與M之間的依賴好處。如果您有不同的看法可以在評論區留言,大家共同學習互相借鑒。在這里,M層只是一個簡單的JavaBean。當然如果加上本文開頭說的DTO,M曾的意義就體現出來了,不過目前還沒有這么做。
在BasePresenter抽象類中,我們還看到了一個recycle()
方法,這個方法是用來清楚View的依賴。因為很多時候Presenter中處理的都是異步耗時操作,如果此時用戶等不耐煩了,推出了當然的界面,那么就很有可能會造成泄漏且如果您使用的是butterknife
這個框架的話,揮發這個框架也會提共一個unbind()
方法,如果這里不清楚View的依賴的話,當用戶退出界面就會發生NullPointException
的異常。所以BasePresenter中提供了這個方法。繼承之后通過使用getView方法獲取依賴的view,注意 使用前需要判斷非空。
現在來看看BaseView接口:
public interface BaseView {
void dialogShow(String message);
void dialogShow();
void dialogDissmiss();
}
這個接口很簡單僅僅只是一個基類,定義了一些公共的方法如這里dialog的顯示與關閉。
由于大部分View層都只是鋪數據,區別只是數據的類型不一樣,因此這里還提供幾個普通的BaseView接口,
處理一種數據的接口
public interface BaseView1<T> extends BaseView{
void getData(T data);
}
處理兩種數據類型的接口:
public interface BaseView2<T,J> extends BaseView{
void getData(T data);
void getData2(J data);
}
等等。這只是偶爾用用的,因為我這里出現的平率比較多所以才加上這寫接口的。其實只需要一個BaseView接口就好了,在定義View層接口的時候基礎BaseView就行。
這里有一個使用的例子,一般項目都會有一個BaseActivity之類的東西。
public class BaseActivity<T extends BasePersent<? extends BaseView>> extends AppCompatActivity implements BaseView {
public static String TAG;
private T presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TAG=getClass().getCanonicalName();
}
@Override
protected void onDestroy() {
if(presenter!=null){
presenter.recycle();
}
super.onDestroy();
}
public T getPresenter() {
return presenter;
}
public void setPresenter(T presenter) {
this.presenter = presenter;
}
@Override
public void showLoading(String message) {
Log.i(TAG,"dialog show "+message);
}
@Override
public void hideLoading() {
Log.i(TAG,"dialog hiden");
}
}
這里BaseActivity實現了BaseView接口,并實現了里面的公共方法(這里是dialog的顯示與關閉)。在onDestory()
方法中,現調用了presenter中的recycle()
方法來釋放引用,這樣不管presenter中做了什么耗時操作只要在getView之前判斷了非空,就避免了泄漏的風險,已經空指針異常的風險了。
在來看看我們View所依賴的Presenter
public class DemoPersent extends BasePersent<DemoPersent.DemoView> {
Service service;
public DemoPersent(DemoView baseView) {
super(baseView);
service=ZillApi.NormalAdapter.create(Service.class);
}
public void doOnClick(String classId){
getView().showLoading("正在加載");
//做了一部分的耗時操作
service.getMainDate(classId, new CallBack() {
@Override
public void success(String str) {
//取消Dialog
if(getView()!=null){
getView().hideLoading();
}
//處理一些數據.......
//返回數據
if(getView()!=null){
getView().updateBtn2(str);;
}
}
});
}
public void doSomthing(){
String str="haha22222";
getView().updateBtn1(str);
}
//Presener所以來的View
public interface DemoView extends BaseView {
void updateBtn1(String str);
void updateBtn2(String str);
}
}
下面看看具體的Activity
public class MainActivity extends BaseActivity<DemoPresenter> implements DemoPresenter.DemoView {
TextView btn,btn1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//指定當前Activity需要的Presneter
setPresenter(new DemoPresenter(this));
btn= (TextView) findViewById(R.id.btn);
btn1= (TextView) findViewById(R.id.btn1);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getPresenter().doOnClick("dsadas");
}
});
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getPresenter().doSomthing();
}
});
}
@Override
public void updateBtn1(String str) {
btn.setText(str);
}
@Override
public void updateBtn2(String str) {
btn1.setText(str);
}
}
如此在也不要擔心泄漏的風險和空指針的問題了。還少些了很多接口,代碼也簡潔多了。在View值會看到很多傻瓜式的鋪數據的過程。
在此結構的基礎上,還可以引入DataBind以及本文開頭說的DTO等進行進一步的簡化。Model層還有很大的提升空間。