Android中使用MVP的简单例子
MVP是一种框架,应该通过学习其是思想,然后进行实践,每个人可能有不同的实现方法,以下是我封装的简单例子。
因为每一个Presenter和View都有一些公共的方法,所以先将其抽取出来,定义Presenter和View的公共父类
image.png
IPresenter:定义一个绑定View的方法,让子类去实现
/**
* 因为我们需要在BasePresenter中拿到 View的对象,所以定义个接口给BasePresenter的继承
* @param <V>
*/
public interface IPresenter<V extends BaseView> {
void attachView(V View);
}
BaseView中可以做一些View共同的方法,例如加载数据失败时,刚开始加载数据时。
package com.example.hp.mvptest.base;
/**
* 这个是所有View实现的基类
* 可以定义一些View的通用的方法
*/
public interface BaseView {
//加载数据失败时
void loadingFailed();
}
接下来定义一个BasePresnter,实现IPresenter的接口,并且通过弱引用持有View,因为防止View被销毁的时候,Presenter还持有View的引用,导致View不能释放,导致内存泄露。
/**
* Presenter的基类,提供绑定View和解绑View的方法
* 为了防止内存泄露,通过弱引用的方式来持有View
*/
public abstract class BasePresenter<V extends BaseView> implements IPresenter<V> {
private WeakReference<V> view;
@Override
public void attachView(V viewInstance) {
view = new WeakReference<>(viewInstance);
}
public WeakReference<V> getView() {
return view;
}
}
接下来定义一个IView的接口,继承了BaseView,这样在具体View的类中只需要实现IView接口就可以了,不需要继承BaseView,不建议使用抽象类,因为Java不支持多继承。
/**
* 定义一个View的接口,定义一个让Presenter更新UI的方法
*/
public interface IView extends BaseView {
void loadingView(Object string);
}
接下来就是一个BaseActivity,为什么要定义这个类呢?因为没一个View都需要实例化一个Presenter的对象,并且绑定View,所以定义一个BaseActivity其中继承了AppCompatActivity,实现了IView,这里可以看出为什么上面的IView要用接口,而不是抽象类。并且定义一个抽象方法:createPresenter(),要求其子类必须实现,初始化Presenter。
/**
* Activity都要继承该类
* @param <V>
* @param <P>
*/
public abstract class BaseActivity<V extends BaseView,P extends BasePresenter<V>> extends AppCompatActivity implements IView {
private P mPresenter;
@SuppressWarnings("unchecked")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter=createPresenter();
if (mPresenter!=null){
//绑定View
mPresenter.attachView((V) this);
}
}
/**
* 加载失败的处理
*/
@SuppressLint("ShowToast")
@Override
public void loadingFailed() {
Toast.makeText(this,"加载失败",Toast.LENGTH_SHORT);
}
/**
* 要求子类创建Presenter
*/
protected abstract P createPresenter();
public P getPresenter() {
return mPresenter;
}
}
很多时候我们View可能是Fragment,但是只需要将继承AppCompatActivity,改成Fragment就可以了。
接下来我就是使用了:
image.png
Activity:
@SuppressLint("Registered")
public class TestActivity extends BaseActivity<IView, TestPresenter> implements View.OnClickListener {
Button button;
TextView textView;
private TestPresenter mTestPresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.text_layout);
button=findViewById(R.id.button);
textView=findViewById(R.id.textView);
mTestPresenter = getPresenter();
button.setOnClickListener(this);
}
@Override
protected TestPresenter createPresenter() {
return new TestPresenter();
}
@Override
public void loadingView(Object string) {
textView.setText((String)string);
}
@Override
public void onClick(View v) {
if ((v.getId())==R.id.button){
mTestPresenter.getData();
}
}
}
Model:
/**
* 因为Model在获取到数据之后,可以通过RxJava来响应,通知Presenter,所以不写接口回调
*/
public class TestModel {
public Observable<String> getDataModel(){
Observable<String> observable=Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext("恭喜您,数据加载成功");
}
});
return observable;
}
}
Presenter
class TestPresenter extends BasePresenter<IView> {
private TestModel mMdodel;
public TestPresenter(){
mMdodel=new TestModel();
}
public void getData(){
mMdodel.getDataModel().subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
getView().get().loadingView(s);
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
getView().get().loadingView("加载失败");
}
});
}
}
以上是个人实践的MVP框架,可能还存在问题,欢迎指教,争取以后改正,谢谢。
完整的代码请看:https://github.com/huang1xiaoxin/MVPTest