咱們接着上一節的內容繼續:GoMVP(一)基於AOP的MVP框架GoMVP的使用json
經過new的方式初始化MarketRepository是不優雅的,不建議這樣作,真正的作法是使用RepositoryInjection:網絡
public class RepositoryInjection implements DataSourceInjection {
@Override
public GoDataSource provideRepository(@NonNull Context context) {
checkNotNull(context);
return new MarketRepository()
}
}
複製代碼
GoMVP提供了一個DataSourceInjection,經過實現DataSourceInjection來建立一個RepositoryInjection,上面onCreate方法內應該這樣寫:框架
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_demo);
//綁定數據倉庫
presenter
.setRepository(new RepositoryInjection().provideRepository(getApplicationContext()));
}
複製代碼
框架支持註解建立Repository,前提是必需要用DataSourceInjection這個接口,咱們下面會講到。ide
使用execute方法執行操做:post
@OnClick({R.id.button2, R.id.button3})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.button2:
presenter.execute(new MarketPresenterAdapter());
break;
case R.id.button3:
break;
}
}
複製代碼
execute的入參是一個PresenterAdapter。spa
@GoBack
public void hahaha(MarketBean bean) {
GoLog.E("MarketBean is backing:" + bean.getValue().getMarketData().getAmountRtv());
}
複製代碼
在Activity任意名稱的方法體上加上@GoBack就能夠接收數據了,接收什麼數據,參數就要指定成什麼類型,好比這裏接收的是MarketBean,若是你在這裏隨便寫個什麼其餘類型這個方法是不會被回調的,爲何呢,由於咱們在執行presenter的excute方法傳入的是MarketPresenterAdapter對象,它指定了類型,返回頭看看MarketPresenterAdapter這個類的targetBeanType方法指定的類型是什麼?沒錯就是MarketBean,若是你想接收MarketPresenterAdapter的數據,就要與它相呼應。指針
@Override
public <T> void targetClazz(Class<T> clazz) {
return MarketBean.class;
}
複製代碼
@GoError
public void error(String errorMsg) {
GoLog.E("error is backing:" + errorMsg);
}
複製代碼
@GoError是用來接收異常或者業務錯誤的註解,接收方法名能夠任意起名,可是參數必定是一個String類型。code
咱們改一下presnter變量的註解爲這樣:對象
@DataSource(RepositoryInjection.class)
private LifecyclePresenter presenter;
複製代碼
@DataSource註解的參數是一個DataSourceInjection類型的class,經過這個註解presenter的建立與Repository的注入一鼓作氣,因此在onCreate方法中就不須要寫綁定的代碼了。token
public class AnnoDemoActivity extends AppCompatActivity{
@DataSource(RepositoryInjection.class)
private LifecyclePresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_demo);
//不須要綁定數據倉庫的代碼了
messagePresenterAdapter = new MessageCountPresenter();
messagePresenterAdapter.setStatus(0);
}
//其餘代碼。。。
}
複製代碼
Note:若是同時存在@Presenter和@DataSource這兩個註解的變量,@DataSource註解的變量會生效,若是調用了presenter的setRepository,最後set的Repository會生效。
有的時候,一個界面可能由多個接口數據組成,咱們這裏有兩個PresenterAdapter,MarketPresenterAdapter和MessageCountPresenter,分別獲取市場信息和消息個數,如何在Activity裏接收呢?
咱們在上面已經指定了MarketPresenterAdapter的targetClazz,如今咱們指定MessageCountPresenter
public class MessageCountPresenter extends BasePresenterAdapter {
//略去部分代碼……
@Override
public Class targetBeanType() {
return NoticeCountBean.class;
}
}
複製代碼
那麼接收的時候能夠這麼寫了:
public class AnnoDemoActivity extends AppCompatActivity{
@BindView(R.id.button2)
Button button;
@BindView(R.id.button3)
Button button3;
@Presenter()
private LifecyclePresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_demo);
//綁定數據倉庫
presenter
.setRepository(new RepositoryInjection().provideRepository(getApplicationContext()));
messagePresenterAdapter = new MessageCountPresenter();
messagePresenterAdapter.setStatus(0);
}
//接收市場數據
@GoBack
public void hahaha(MarketBean bean) {
GoLog.E("MarketBean is backing:" + bean.getValue().getMarketData().getAmountRtv());
}
//接收消息個數數據
@GoBack
public void receiverData(NoticeCountBean bean) {
GoLog.E("NoticeCountBean is backing:" + bean);
}
//接收全部的異常返回
@GoError
public void error(String errorMsg) {
GoLog.E("error is backing:" + errorMsg);
}
//接收消息個數數據異常返回
@GoError
public void errorNoticeCount(NoticeCountBean bean,String errorMsg) {
GoLog.E("error is backing:" + errorMsg);
}
@OnClick({R.id.button2, R.id.button3})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.button2:
presenter.execute(new MarketPresenterAdapter());
break;
case R.id.button3:
presenter.execute(messagePresenterAdapter);
break;
}
}
}
複製代碼
方法hahaha和方法receiverData分別接收MarketBean和NoticeCountBean,接收什麼實例和方法名無關,只於方法參數的具體類型有關。
一樣的,不一樣的execute操做會返回不一樣的異常錯誤信息,若是不單獨指定,上面的error方法能夠接收它們全部的異常,但有種狀況,可能會針對不一樣的execute處理不一樣的異常,這種狀況下就須要使用類型肯定了,和接收同樣,增長一個包含類型的參數方法,好比errorNoticeCount方法,這個方法的第一個參數是NoticeCountBean對象,這樣經過@GoError這個註解,就能夠接收到NoticeCount的錯誤異常,而只會接收到NoticeCount形成的業務異常。
PS:須要注意的是,errorNoticeCount接收的只是業務上的錯誤,好比token失效這樣的。若是碰到相似與(IO,超時,null指針,Json解析等)這樣的異常,只會在error裏返回,不會在errorNoticeCount返回。而error會接收全部的錯誤和異常包括errorNoticeCount返回的業務異常error也會接收到。
在擴展Presenter,也就是PresenterAdapter時,有兩個方法:
@Override
public Pair onSuccessCodePair() {
return new Pair("success","true");
}
@Override
public String onErrorMessageKey() {
return "message";
}
複製代碼
框架中默認使用Json返回數據的格式,想象一下當一個數據返回時,咱們可能須要處理一下再使用,最多見的是業務層面的成功與失敗,在定義的通常格式的json中最外層的屬性裏必定會有一個判斷業務成功與失敗的字段,好比successCode,responseCode等等,你把這個字段告訴框架,而且告訴框架這個字段表示成功的值是什麼。這裏的例子告訴框架,表示請求結果的成功或失敗的字段名爲"success",表示成功的值爲"true",這樣框架處理數據時,若是發現沒有這個字段,或者有「success」這個字段但值不爲"true"時(注意這裏的值是個字符串的true,這是由於業務具體而定,也許是個整形的0,或者boolean的true),將會認爲是個錯誤的請求,把結果經過@GoError標註的方法在Activity返回。
而onErrorMessageKey方法是用來肯定,當返回業務錯誤時,咱們須要解析哪一個字段來返回錯誤信息,好比當咱們執行一些敏感操做時,會攜帶token 去客戶端作驗證,若是token失效會返回一個錯誤碼,若是返回字段中有錯誤信息字段,咱們能夠直接告訴框架這個字段是什麼,這裏這個字段叫「message」,這樣當框架發現success字段返回的不是「true」時,就會解析message字段,將錯誤提示內容,好比「token失效」經過@GoError修飾的方法返回。固然框架沒法判斷多種狀況,若是覺的這兩個方法沒法知足使用者的業務需求,咱們還能夠經過「攔截」返回數據,來處理多變的業務邏輯。
PS:若是不處理上面兩個方法,會發生什麼?
若是不處理上面兩個方法,框架將不會關心業務異常,會把數據生成的JavaBean返回到View層,而處理異常的@GoError修飾的方法將不會收到業務異常,只會收到運行時的異常(好比IO,網絡,解析json等這些異常)由於使用者並無定義。
若是想在框架處理返回數據以前對數據「動手腳」,咱們能夠在咱們本身的PresenterAdapter上實現InterceptGoBack這個接口,咱們下一節介紹「攔截」。