mvp结构图.png
我觉得这张图是有问题的,问题在于presenter把请求转交给model,model应该把处理结果返回给presenter,这张图是没有反映这个过程的。
正确的mvp的结构图是这样子的
mvp结构
我们先看下能从这张图中得到哪些信息?
public LoginActivity extends Activity{ private EditText mUserNameView, mPasswordView; private Button mLoginView; public void initViews(){.......各种findViewById.....代码//给登陆按钮加监听器mLoginView.OnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String userName = mUserNameView.getText();String password = mPasswordView.getText();//验证用户输入的密码是否合法if(!validate(userName) || !validate(password)){ 告诉用户输入的用户名或密码不合法} else{ //开始登陆 login(userName,password);}}}); } //登陆方法,用伪代码来写下网络请求 private void login(String userName,String password){ //增加登录进度对话框给用户友好用户体验 显示登录进度对话框... HttpClient.getInstance().login(userName,password,new ResponseListener(){public void failed(Failed failed){ 把登录进度对话框消失... 做失败相关的处理工作,比如给用户提示 把密码输入框清空,还比如登陆次数限制等}public void success(Response response){ 把登录进度对话框消失... 做成功相关的处理工作 //暂且把用户信息的类叫做UserInfo,从json中解析数据,假设response.getContent()存在 String jsonContent = response.getContent(); JsonObject jsonObject = new JsonObject(jsonContent); UserInfo userInfo = new UserInfo(); userInfo.name = jsonObject.optString("name"); userInfo.userId = jsonObject.optString("userId"); 其他字段的解析...... //保存userInfo信息到数据表中,假设userDatabase已经存在 userDatabase.save(userInfo); 跳到app的主页}}); } //验证给定的字符串是否合法,true 合法,false 不合法 private boolean validate(String str){ } }我们回忆了“万能”LoginActivity的代码后,开始重构。
//管理登录的类,它是单例的,这就不写单例方法了 public class LoginManager{ //登录的监听器 public static interface LoginListener{//登录成功void onSuccessLogin(UserEntity user);//登录失败void onFailedLogin(Failed failed); } //登录方法 public void login(String name,String password,final LoginListener loginListener){//假设HttpClient是一个请求网络服务的类HttpClient.getInstance().login(userName,password,new ResponseListener(){public void failed(Failed failed){loginListener.onFailedLogin(failed);}public void success(Response response){ //假设UserParse类已经存在,主要用来从response中解析UserEntity UserEntity userEntity = UserParse(response.getContent()); //假设userDatabase是数据库存储类 userDatabase.store(userEntity); //还可以把userEntity存入内存中,这得根据业务需求进行处理loginListener.onSuccessLogin(userEntity);}}); } }登录的model层我们没有做的那么复杂,比如把服务器返回的用户信息存储在内存中,把服务器返回的token存储在磁盘中,实现自动登录功能等,本例子只是一个特别简单的登录功能,实际应用中登录需要考虑很多的东西,登录的modle层到此重构完毕。
//登录的条约接口,分别定义了登录view的一些方法,和登录presenter的一些方法public interface LoginContract{ //需要view层来实现的登录view接口,IView是所有view的基类 interface ILoginView extends IView{void onShowSuccessLoginView(UserInfo userInfo);void onShowFailedLoginView(int failed);void showLoginingView();void dissLoginingView(); } //定义了登录presenter的一些方法,IPresenter是所有Presenter的基类 interface ILoginPresenter extends IPresenter<ILoginView>{void login(String name,String password); } } public interface IView{ void initView(); } //IPresenter提供了一些基础方法,其实这些方法是对应Activity或Fragment的生命周期方法 public interface IPresenter<V extends IVew>{ void onStop();void onResume();void onDestroy(); void onPause(); void onStart(); void init(V view); } //登录的presenter public class LoginPresenter implements ILoginPresenter{ private ILoginView mLoginView; private LoginManager mLoginManager = LoginManager.getInstance(); public void init(ILoginView loginView){mLoginView = loginView;mLoginView.initView(); } public void login(String name,String password){//验证name,password的合法性,if(validate(name) && validate(password)){//假设NormalThread.exe方法可以让操作在普通线程里执行 mLoginView.showLoginingView();NormalThread.exe(new Runnable(){public void run(){mLoginManager.login(name,password,new LoginListener(){ public void onSuccessLogin(UserEntity userEntity){ //UserMapper类,负责把底层的UserEntity转化为view层使用的UserInfo UserInfo userInfo = UserMapper.map(userEntity); //下面的代码在ui线程中执行,这就不写具体的实现了mLoginView.onShowSuccessLoginView(userInfo);mLoginView.dissLoginingView(); } public void onFailedLogin(Failed failed){ //下面的代码在ui线程中执行,这就不写具体的实现了 mLoginView.onShowFailedLoginView(failed.failedState); mLoginView.dissLoginingView(); }});}}}else{//假设1代表账号,密码不合法mLoginView.onShowFailedLoginView(1);} } }以上登录的Presenter层的伪代码都是关键代码,让我们看下以上代码都做了什么?
public abstract class BaseActivity extends FragmentActivity{ private Set<IPresenter> mAllPresenters = new HashSet<IPresenter>(1); /** * 获取layout的id,具体由子类实现 * @return */ protected abstract int getLayoutResId(); /** *需要子类来实现,获取子类的IPresenter,一个activity有可能有多个IPresenter */ protected abstract IPresenter[] getPresenters(); //初始化presenters, protected abstract void onInitPresenters(); /** * 从intent中解析数据,具体子类来实现 * @param argIntent */ protected void parseArgumentsFromIntent(Intent argIntent){ }private void addPresenters(){IPresenter[] presenters = getPresenters();if(presenters != null){for(int i = 0; i < presenters.length; i++){mAllPresenters.add(presneters[i]);}} }@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState);setContentView(getLayoutResId()); if(getIntent() != null){parseArgumentsFromIntent(getIntent()); }addPresenters(); onInitPresents(); } @Override protected void onResume() {super.onResume();//依次调用IPresenter的onResume方法 for (IPresenter presenter:mAllPresenters ) { if(presenter != null){ presenter.onResume(); } } } ...其他生命周期方法也是类似,调用IPresenter中相应的生命周期方法... }基础设施已经ok了,这时候我们就该重构"万能“LoginActivity了。
public class LoginActivity extends BaseActivity implements LoginConstract.ILoginView{ private LoginPresenter mLoginPresenter = new LoginPresenter(); protected int getLayoutResId(){return R.layout.activity_login; } protected IPresenter[] getPresenters(){return new IPresneter[]{ mLoginPresenter}; } //初始化presenters, protected void onInitPresenters(){mLoginPresenter.init(this); } public void initView(){ ...初始化view的代码... // mLoginButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {mLoginPresenter.login(name,password);} }); } public void onShowSuccessLoginView(UserInfo userInfo){....显示登录成功界面.... } public void onShowFailedLoginView(int failed){...显示登录失败界面... } public void showLoginingView(){...显示登录进度条对话框... } public void dissLoginingView(){...消失登录进度条对话框... } }我们着重说下基础设施BaseActivity: