上一節我們將了GoMVP的進階使用:基於AOP的MVP框架(二)GoMVP進階註解
如果想在框架處理返回資料之前對資料“動手腳”,我們可以在我們自己的PresenterAdapter上實現InterceptGoBack這個介面,我們拿上面的MarketPresenterAdapter舉個例子:
4、"攔截"返回資料,優先處理
public class MarketPresenterAdapter extends PresenterAdapter implements InterceptGoBack<MarketBean>{
@Override
public Observable onCreateObservable(Context context, RetrofitConverter retrofitConverter) {
Retrofit retrofit = retrofitConverter.createRetrofit();
ApiServer apiServer = retrofit.create(ApiServer.class);
HashMap<String, Object> map = new HashMap<>();
map.put("請求引數1",0);
map.put("請求引數2","123");
Observable<HttpResult<SecretKeyBean>> observable = apiServer.getSecretKey(map);
return observable;
}
@Override
public Pair onSuccessCodePair() {
return new Pair("success","true");
}
@Override
public String onErrorMessageKey() {
return "message";
}
@Override
public Class targetBeanType() {
return MarketBean.class;
}
@Override
public boolean intercept(MarketBean marketBean) {
//預先處理marketBean
marketBean.setMessage("我被處理過了");
return false;
}
}
複製程式碼
實現InterceptGoBack介面後,還要實現一下它的intercept方法,方法的回撥引數是你想要預先處理的JavaBean,這裡是MarketBean,它的返回值很關鍵,
如果返回false,說明不會攔截流程繼續交給框架去處理,View層會接收到回撥,如果返回true,證明此處要攔截剩下的流程,不在交由框架去處理和返回到View層。
第二點需要注意的是,intercept處理完的Bean資料後,如果接著交給框架繼續處理(返回false),框架會用處理過的資料繼續執行剩下的邏輯。
5、使用@GoActionBack
有一種場景,如果一個頁面的多個介面呼叫返回的資料型別是一致的,我們想單獨處理每一個請求,我們可以使用@GoActionBack註解來接收回撥:
public class AnnotationDemoActivity extends AppCompatActivity implements ExecuteStatusView {
private static final String DELETE = "action_delete";
private static final String ADD = "action_add";
@BindView(R.id.button2)
Button button;
@BindView(R.id.button3)
Button button3;
/**
* 注入Presenter,RepositoryInjection,
* RepositoryInjection必須為DataSourceInjection的子類
*/
@DataSource(RepositoryInjection.class)
private LifecyclePresenter presenter;
private MessageCountPresenter messagePresenterAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_demo);
messagePresenterAdapter = new MessageCountPresenter();
messagePresenterAdapter.setStatus(0);
presenter.registerExecuteStatus(this);
}
/**
* test @GoBack
* @param bean
*/
@GoBack
public void hahaha(MarketBean bean) {
GoLog.E("MarketBean is backing:" + bean.getMessage());
}
/**
* 這裡的action要對應Adapter裡的action
* test @GoActionBack
* @param bean
*/
@GoActionBack(action = DELETE)
public void receiverDeleteData(MarketBean bean) {
GoLog.E("MarketBean delete is backing:" + bean);
}
@GoActionBack(action = ADD)
public void receiverAddData(MarketBean bean) {
GoLog.E("MarketBean add is backing:" + bean);
}
@OnClick({R.id.button2, R.id.button3})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.button2:
new Thread(() -> {
presenter.bindPresenterAdapter(new MarketPresenterAdapter(DELETE));
presenter.execute();
}).start();
break;
case R.id.button3:
presenter.execute(new MarketPresenterAdapter(ADD));
break;
}
}
}
複製程式碼
上面的例子中,我們增加來三個回撥方法,這三個回撥的引數都是同一個型別MarketBean,其中兩個使用了@GoActionBack註解,改註解引數是個字串型別。同時在執行adapter時,給adapter傳遞了一個值,這個值就是註解上定義的字串的值,這個值需要在adapter中使用,像這樣:
public class MarketPresenterAdapter extends BasePresenterAdapter implements InterceptGoBack<MarketBean>{
private String action;
.
.
public MarketPresenterAdapter(String action) {
this.action = action;
}
//if action 為null或者"",則被@GoActionBack修飾的方法接收不到回撥。
@Override
public String action() {
return action;
}
.
.
}
複製程式碼
實現action方法,告訴框架這個Adapter和具體的接收事件的方法之間的關係,這樣在框架執行完任務後才能找到正確的回撥方法。比如:
presenter.execute(new MarketPresenterAdapter(ADD));
複製程式碼
當,執行完成後,該方法會收到回撥:
@GoActionBack(action = ADD)
public void receiverAddData(MarketBean bean) {
GoLog.E("MarketBean add is backing:" + bean);
}
複製程式碼
PS:注意上面三個回撥方法,其中兩個分別被@GoActionBack(action = ADD)與,@GoActionBack(action = DELETE)修飾,它們相對於使用了不同的action的Adapter,其中還有一個被@GoBack修飾的回撥,這個回撥的型別同樣是MarketBean,所以不管使用那種action的Adapter,這個方法都會收到回撥,因為@GoBack只認型別。而@GoActionBack多了層維度,不只認型別,還認action。
6、使用OnExecuteListener監聽excute狀態
實現ExecuteStatusView介面便可以監聽excute執行狀態
public class AnnoDemoActivity extends AppCompatActivity implements ExecuteStatusView {
@DataSource(RepositoryInjection.class)
private LifecyclePresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_demo);
//註冊進度監聽
presenter.registerExcuteStatus(this);
}
@Override
public void onExecuteBegin() {
//loading View show。。。
}
@Override
public void onExecuteFinish() {
//loading View close。。。
}
//其他程式碼。。。
}
複製程式碼
目前只提供了開始和結束,分別為onExecuteBegin和onExecuteFinish,同時需要注意的是,如果多次執行excute方法,每執行一次excute,ExecuteStatusView的回撥都會被執行,注意。
7、擴充套件Cache
在初始化MarketRepository時,需要實現GoDataSource介面,其中getGoCache的返回值用來指定資料倉儲的具體快取實現:
public class MarketRepository implements GoDataSource {
@Override
public <B> GoDataSource loadDataFromRepository(Observable<B> observable, Observer observer) {
observable.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
return this;
}
/**
* 指定具體快取方案
**/
@Override
public GoCache getGoCache(Context context) {
return new DefaultGoCache(context);
}
@Override
public RetrofitConverter onCreateRetrofitConverter() {
return new MainRetrofit();
}
@Override
public <T> void targetClazz(Class<T> clazz) {
}
}
複製程式碼
在getGoCache方法返回了一個DefaultGoCache物件,這是框架提供的快取實現,它實現了GoDataSource.GoCache介面,比如要實現自己的快取方案,可以這樣:
1、實現GoDataSource.GoCach介面
public class MyGoCache implements GoDataSource.GoCache<String, String> {
private final Context context;
public MyGoCache(Context context) {
this.context = context;
}
@Override
public void onAdd(String key, String value) {
SharedPUtil.setParam(context, key, value);
GoLog.D(TAG + "cache :" + "key:" + key + "....value:" + value);
}
@Override
public String onGet(String key) {
String s = SharedPUtil.getParam(context, key);
GoLog.D(TAG + "cache out :" + "key:" + key + "....value:" + s);
return s;
}
}
複製程式碼
2、這裡需要實現兩個方法,一個onAdd,一個onGet,分別對應新增和獲取,這裡我們用SharedPreferences來作為快取方案。
3、在實現我們自己的Repository時,把自定義的MyGoCache設定到我們的Repository裡:
/**
* 指定具體快取方案
**/
@Override
public GoCache getGoCache(Context context) {
//自定義的GoCache/
return new MyGoCache(context);
}
複製程式碼
8、Fragment
在Fragment中一樣可以使用,這裡就不單獨寫例子了,但需要注意的是,如果使用註解初始化presenter,presenter只可以在onCreateView的方法內以及其後的生命週期使用,之前比如onCreate中使用就會被報空指標異常,那是因為presenter沒有初始化的原因,框架會在Fragment的onCeateView方法中初始化presenter。
基於AOP的實現原理
上面介紹了GoMVP的使用方式,我們姐下來介紹它是如何做到只用一行註解就可以完成Presenter的初始化和Repository的初始化與繫結,如何通過一行註解接收資料而不需要通過業務程式碼去實現,這裡就要提到一個AOP的工具AspectJ,關於AspectJ的使用網上有很多的例子比如這一篇 www.jianshu.com/p/f90e04bcb… ,大家可以先了解一下AspectJ的基本使用。
GoMVP原始碼地址:github.com/wuchengithu…
結語:
GoMVP是一個基於AOP的MVP框架,在開發過程中可以減少模版程式碼的書寫,提高開發效率的同時也具備著MVP架構的擴充套件性,同時框架也在探索更多的AOP特性,會不斷的進行優化和迭代。下面幾章將會介紹GoMVP的實現原理。