GoMVP(三)GoMVP的進階註解
上一節我們將了GoMVP的進階使用:ofollow,noindex">GoMVP(二)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的基本使用。