前言
通过一个小的登录功能模块案例,帮助大家了解MVP。最终实现一个结合Rxjava2,Retrofit 的MVP通用框架。代码放到github上。(如有错误之处,请在评论区指出,谢谢。如果感觉写的不错,请点赞,关注,谢谢。)
目录:
Android MVP-编程思想1(什么是MVC-MVP-MVVM模式?)
Android MVP-编程思想2(代码实现初级版)
Android MVP-编程思想3(内存泄露问题处理,基类封装,有没有必要再使用软引用?)
Android MVP-编程思想4(AOP思想-动态代理运用,反射创建M层实例对象)
Android MVP-编程思想5(如何处理多个P层的问题?)
Android MVP-编程思想6(依赖注入多个P层优化—注解,反射)
Android MVP-编程思想7(为什么使用代理类抽取通用方法而不是工具类?,基类BaseMvpFragment)
未完待续--------
Android MVP-编程思想8(集成Rxjava2,Retrofit)
上一小节就是讲解多个P的处理思想。非常简单,使用容器存储就Ok了。这一小节,讲解使用如何使用注解和反射形式创建P的实例对象。目的有两个(1)是减少基类(父类)和子类的直接依赖。基类不需要通过createPresenter方式 注入P的引用,(2)减少代码,去掉繁琐的创建操作。
每次都要实现createPresenter()方法,这种依赖注入的方式能否优化?
解决思路一句话:注解扫描,反射创建实例化对象
看代码
创建注解类 InjectPresenter
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface InjectPresenter {
}
在LoginActivity 使用InjectPresenter
@InjectPresenter
private LoginPresenter loginPresenter;
改动BaseMvpActivity 扫描注解,反射创建P对象
private void initPresenterByScanAnnotation() {
mPresenters = new ArrayList<>();
//获得已经申明的变量,包括私有的
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
//获取变量上面的注解类型
InjectPresenter injectPresenter = field.getAnnotation(InjectPresenter.class);
if (injectPresenter != null) {
try {
Class<? extends BasePresenter> type = (Class<? extends BasePresenter>) field.getType();
BasePresenter mInjectPresenter = type.newInstance();
mInjectPresenter.attachView(this);
field.setAccessible(true);
field.set(this, mInjectPresenter);
mPresenters.add(mInjectPresenter);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassCastException e) {
e.printStackTrace();
throw new RuntimeException("SubClass must extends Class:BasePresenter");
}
}
}
}
BaseMvpActivity 修改之后的代码
public abstract class BaseMvpActivity extends AppCompatActivity {
protected List<BasePresenter> mPresenters;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View rootView;
final Object layout = getLayout();
if (layout instanceof Integer) {
rootView = View.inflate(this, (int) getLayout(), null);
} else if (layout instanceof View) {
rootView = (View) getLayout();
} else {
throw new ClassCastException("type of setLayout() must be int or View!");
}
setContentView(rootView);
initPresenterByScanAnnotation();
afterCreate();
}
@Override
protected void onDestroy() {
super.onDestroy();
for (BasePresenter p : mPresenters) {
p.detachView();
}
mPresenters.clear();
mPresenters = null;
}
private void initPresenterByScanAnnotation() {
mPresenters = new ArrayList<>();
//获得已经申明的变量,包括私有的
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
//获取变量上面的注解类型
InjectPresenter injectPresenter = field.getAnnotation(InjectPresenter.class);
if (injectPresenter != null) {
try {
Class<? extends BasePresenter> type = (Class<? extends BasePresenter>) field.getType();
BasePresenter mInjectPresenter = type.newInstance();
mInjectPresenter.attachView(this);
field.setAccessible(true);
field.set(this, mInjectPresenter);
mPresenters.add(mInjectPresenter);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassCastException e) {
e.printStackTrace();
throw new RuntimeException("SubClass must extends Class:BasePresenter");
}
}
}
}
@SuppressWarnings("ConstantConditions")
protected <T extends View> T $(@IdRes int viewId) {
return findViewById(viewId);
}
public void showProgress(boolean isShow) {
if (isShow) {
Log.i("mvp_", "显示等待框");
} else {
Log.i("mvp_", "隐藏等待框");
}
}
public void showToast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}
protected abstract Object getLayout();
protected abstract void afterCreate();
}
LoginActivity 修改之后的代码
public class LoginActivity extends BaseMvpActivity implements LoginContract.IView {
@InjectPresenter
private LoginPresenter loginPresenter;
@Override
protected Object getLayout() {
return R.layout.activity_main;
}
@Override
protected void afterCreate() {
$(R.id.btn_login).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
loginPresenter.onClickLogin("xxx", "xxx");
}
});
}
@Override
public void goToMainActivity() {
runOnUiThread(new Runnable() {
@Override
public void run() {
//todo 登录成功跳转到主界面
Log.i("mvp_", "登录成功跳转到主界面");
}
});
}
@Override
public void showProgress(boolean isShow) {
if (isShow) {
Log.i("mvp_", "显示等待框");
} else {
Log.i("mvp_", "隐藏等待框");
}
}
@Override
public void showToast(String str) {
Toast.makeText(this, str, Toast.LENGTH_LONG).show();
}
}
很明显优化之后的依赖注入方式使得代码更精简,同时也减少基类(父类)和子类的依赖。
下一节实现BaseMvpFragment基类。同时使用代理类的方式抽离通用方法。