上一节我们将了GoMVP的进阶使用: GoMVP(二)GoMVP的进阶注解
如果想在框架处理返回数据之前对数据“动手脚”,我们可以在我们自己的PresenterAdapter上实现InterceptGoBack这个接口,我们拿上面的MarketPresenterAdapter举个例子:
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),框架会用处理过的数据继续执行剩下的逻辑。
有一种场景,如果一个页面的多个接口调用返回的数据类型是一致的,我们想单独处理每一个请求,我们可以使用@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。
实现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的回调都会被执行,注意。
在初始化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); } 复制代码
在Fragment中一样可以使用,这里就不单独写例子了,但需要注意的是,如果使用注解初始化presenter,presenter只可以在onCreateView的方法内以及其后的生命周期使用,之前比如onCreate中使用就会被报空指针异常,那是因为presenter没有初始化的原因,框架会在Fragment的onCeateView方法中初始化presenter。
上面介绍了GoMVP的使用方式,我们姐下来介绍它是如何做到只用一行注解就可以完成Presenter的初始化和Repository的初始化与绑定,如何通过一行注解接收数据而不需要通过业务代码去实现,这里就要提到一个AOP的工具AspectJ,关于AspectJ的使用网上有很多的例子比如这一篇 www.jianshu.com/p/f90e04bcb… ,大家可以先了解一下AspectJ的基本使用。