**版权声明:本文为小斑马伟原创文章,转载请注明出处!
上一篇介绍的是一个基础的MVP架构的登录功能。还没有进行代码的封装。它的View于Model还是有一定的耦合的。本篇目标解耦View于Model,Base基类封装,实现契约管理MVP。
一、Base抽取
类臃肿的原因是,Modle层,View层,Presenter层没有抽取,导致每一个功能模块都对应着一个M,V,P三个类。
public interface BaseView {
void showLoading();
void hideLoading();
}
Model层抽取
public interface BaeModel {
}
Presenter层抽取
//T代表View E代表Model
public abstract class BasePresenter {
public Context mContext;
public T mView;
public E mModel;
public WeakReference mViewRef;
public void setViewAndModel(T view,E model) {
mViewRef = new WeakReference(view);
this.mView = view;
this.mModel = model;
}
public T getView() {
if (isAttach()) {
return mViewRef.get();
} else {
return null;
}
}
public boolean isAttach() {
return null != mViewRef && null != mViewRef.get();
}
public void onDettach() {
if (null != mViewRef) {
mViewRef.clear();
mViewRef = null;
}
}
Presenter层仍然要持有Model,View的强引用,在 setViewAndModel这个方法中,对两个对象进行赋值,这里可以看到我简单是采用了弱引用的方式去保存这个View的对象引用,减少内存泄露的可能性。
对Activity封装
二、契约管理MVP
LoginContract类将三个接口合并在一个,如下:
public class LoginContract {
interface Model extends BaeModel {
void login(String userName, String password, UserLoginListener userLoginListener);
Observable rxLogin(String userName,String passWord);
}
interface View extends BaseView {
void success();
void failed();
void clear();
}
abstract static class Presenter extends BasePresenter {
abstract void login(String userName,String passWord);
abstract void rxLogin(String userName,String passWord);
abstract void clear();
}
}
将相同模块的M,V,P三层定一个合约,放在一块,统一管理。我们还需要看一个Activity封装的基类。
public abstract class BaseActivity extends AppCompatActivity {
public Context activity;
public T mPresenter;
public E mModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(initLayout());
activity = this;
mPresenter = MVPUtils.getT(this,0);
mModel = MVPUtils.getT(this,1);
if(null!=mPresenter) {
mPresenter.mContext = this;
}
initView();
initListener();
initPresenter();
}
protected abstract void initListener();
protected abstract void initView();
protected abstract int initLayout();
protected abstract void initPresenter();
}
通过getGenericSuperclass方法可以获取当前对象的直接超类的 Type。
public class MVPUtils {
public static T getT(Object o, int i) {
try {
return ((Class) ( (ParameterizedType)(o.getClass().getGenericSuperclass())).getActualTypeArguments()[i]).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
三、Model层的实现
第一个方法使用自定义回调接口实行,第二种使用RxJava方式实现
public class NewLoginModel implements LoginContract.Model {
@Override
public void login(final String userName,final String passWord,final UserLoginListener userLoginListener) {
new Handler().postDelayed(new Runnable(){
@Override
public void run() {
if("weiwei".equals(userName) && "123".equals(passWord)) {
userLoginListener.loginSuccess();
} else {
userLoginListener.loginFail();
}
}
},3000);
}
@Override
public Observable rxLogin(final String userName,final String passWord) {
return Observable.create(new Observable.OnSubscribe() {
@Override
public void call(Subscriber super String> subscriber) {
SystemClock.sleep(2000);
if("weiwei".equals(userName) && "123".equals(passWord)) {
subscriber.onNext("SUCCESS");
subscriber.onCompleted();
} else {
subscriber.onNext("FAILED");
subscriber.onCompleted();
}
}
});
}
}
三、Presenter层的实现
单纯的MVP架构在业务层是直接调用,而Android的自身不建议在主线程进行网络请求,为了保证我们业务运行于一个单独的线程,主线程只运行界面渲染,引入RxJava进行线程调度控制。具体的RxJava详细介绍见-RxJava
public class NewLoginPresenter extends LoginContract.Presenter {
@Override
void login(String userName, String passWord) {
final LoginContract.View mView = getView();
if(TextUtils.isEmpty(userName)||TextUtils.isEmpty(passWord)) {
Toast.makeText(mContext,"请输入你的用户名和密码",Toast.LENGTH_SHORT).show();
} else {
mView.showLoading();
mModel.login(userName, passWord, new UserLoginListener() {
@Override
public void loginSuccess() {
mView.success();
mView.hideLoading();
}
@Override
public void loginFail() {
mView.failed();
mView.hideLoading();
}
});
}
}
@Override
void rxLogin(String userName, String passWord) {
if(TextUtils.isEmpty(userName)||TextUtils.isEmpty(passWord)) {
Toast.makeText(mContext,"请输入你的用户名和密码",Toast.LENGTH_SHORT).show();
} else {
mView.showLoading();
mModel.rxLogin(userName,passWord)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber() {
@Override
public void onCompleted() {
mView.hideLoading();
}
@Override
public void onError(Throwable e) {
mView.hideLoading();
}
@Override
public void onNext(String s) {
mView.hideLoading();
Toast.makeText(mContext,s,Toast.LENGTH_SHORT).show();
}
});
}
}
@Override
void clear() {
mView.clear();
}
}
四、Activity的实现
public class NewMVPLoginActivity extends BaseActivity implements View.OnClickListener, LoginContract.View {
private EditText editAccount;
private EditText editPassWord;
private AppCompatButton btnLogin;
private AppCompatButton btnClear;
private ProgressDialog progressDialog;
@Override
protected void initListener() {
btnLogin.setOnClickListener(this);
btnClear.setOnClickListener(this);
}
@Override
protected void initView() {
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("login process,Watting...");
progressDialog.setCancelable(false);
editAccount = (EditText)findViewById(R.id.edit_account);
editPassWord = (EditText)findViewById(R.id.edit_password);
btnLogin = (AppCompatButton)findViewById(R.id.btn_login);
btnClear = (AppCompatButton)findViewById(R.id.btn_delete);
}
@Override
protected int initLayout() {
return R.layout.activity_main;
}
@Override
protected void initPresenter() {
mPresenter.setViewAndModel(this,mModel);
}
@Override
public void showLoading() {
progressDialog.show();
}
@Override
public void hideLoading() {
progressDialog.dismiss();
}
@Override
public void success() {
Toast.makeText(NewMVPLoginActivity.this,"登录成功",Toast.LENGTH_LONG).show();
}
@Override
public void failed() {
Toast.makeText(NewMVPLoginActivity.this,"登录失败",Toast.LENGTH_LONG).show();
}
@Override
public void clear() {
editAccount.setText("");
editPassWord.setText("");
}
@Override
public void onClick(View view) {
switch(view.getId()) {
case R.id.btn_login:
// mPresenter.login(editAccount.getText().toString(),editPassWord.getText().toString());
mPresenter.rxLogin(editAccount.getText().toString(),editPassWord.getText().toString());
break;
case R.id.btn_delete:
mPresenter.clear();
break;
}
}
}
具体效果图如下: