上一节我们将了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的实现原理。