目前网上有很多MVP模式的案例代码,但是大部分的MVP模板代码比较多使用不方便,这篇文章讲解如何使用注解和apt方式来简化我们的模板代码
1. 优化之前的代码量
public class Main3ActivityActivity extends BaseActivity implements Main3ActivityContract.View {
//presenter 对象注解
@Inject
VideoPlayerPresenter mPresenter;
@Override
protected int getLayout() {
return R.layout.activity_main3;
}
@Override
protected void initInject() {
//绑定this到Component
DaggerActivityComponent.builder()
.appComponent(FrameApplication.mApplication.getAppComponent())
.build()
.inject(this);
}
@Override
protected void attacView() {
//将当前的this传入presenter 以方便presenter 回调组件
mPresenter.attacView(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
//注销释放资源
mPresenter.detachView();
}
@Override
protected void initViewData() {
}
}
复制代码
在上面的代码中我们可以看到 initInject attacView detachView是每个页面都需要做的,有些人将这些封装到了BaseActivity里,通过泛型在继承父类时来将presenter 传入父类在父类中统一初始化attacView detachView,但是平时我们的presenter是需要复用的,可能一个activity需要多个presenter那么 泛型传入方式显然不合适,而且绑定Component的时候需要传入当前的子类对象 如果在父类里初始化initInject 显然是不合理的会报错,因为在ActivityComponent需要传入当前类的对象而不是父类BaseActivity,所以我们做的就是简化这三部的代码.
2. 优化后的代码
@InjectActivity
public class ExampleActivity extends BaseActivity {
@Inject
@AttachView
VideoPlayerPresenter mPresenter;
@Override
protected int getLayout() {
return R.layout.activity_search;
}
@Override
protected void initViewData() {
}
}
复制代码
可以到优化或的代码量非常少只需要 用到 @InjectActivity @AttachView 两个注解就可以省略掉上面的三个方法下面我们讲下这两个注解的作用
@InjectActivity : 这个是替代initInject方法的 通过apt技术编译时生成不同的initInject方法的class,然后在BaseActivity里使用反射将当前class绑定到Component中 编译生成的class
基类使用反射调用编译生成的class
//判断当前类需不需要编译时生成绑定类
InjectActivity annotation = this.getClass().getAnnotation(InjectActivity.class);
if (annotation != null) {
InjectTools.inject(this);
}
复制代码
InjectTools.java 通过反射调用绑定类中的绑定方法
public class InjectTools {
private static final ArrayMap<String, Object> injectMap = new ArrayMap<>();
public static void inject(Object object) {
String className = object.getClass().getName();
try {
Object inject = injectMap.get(className);
if (inject == null) {
Class<?> aClass = Class.forName(className + "$$InjectUtils");
inject = aClass.newInstance();
injectMap.put(className, inject);
}
Method m1 = inject.getClass().getDeclaredMethod("inject", object.getClass());
m1.invoke(inject, object);
} catch (Exception e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
}
}
}
复制代码
@AttachView : 这个注解是用来简化 attacView(this)的 如果我们需要多个presenter 那么每个presenter 都需要调用attacView(this) 所以 给每个presenter加上这个注解在 基类里直接同意的获取presenter 并且调用attacView(this)
PresenterDispatch mPresenterDispatch = PresenterProviders.inject(this).presenterCreate();
mPresenterDispatch. attachView(this, getLifecycle());
//拿到所有使用到AttachView注解的字段,然后存储到集合中,统一进行attachView
private PresenterProviders(Object obj) {
checkNull(obj);
for (Field field : obj.getClass().getDeclaredFields()) {
//获取字段上的注解
Annotation[] anns = field.getDeclaredAnnotations();
if (anns.length < 1) {
continue;
}
if (anns[0] instanceof AttachView) {
String canonicalName = field.getType().getName();
try {
mPresenterStore.put(canonicalName, (BasePresenter) field.get(obj));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
复制代码
我们的detachView 销毁资源使用的是lifecycle 来做的 在presenter的基类里统一做了资源销毁的操作,我们在上一步的 attachView的时候传入了一个当前的getLifecycle()对象
@Override
public void onDestroy(LifecycleOwner owner) {
detachView();
}
复制代码
最后感兴趣的同学可以去github上查看代码
项目地址 : github.com/liuzeze/Sup…