Android之MVP模式

来源:互联网 发布:c 源码下载 编辑:程序博客网 时间:2024/05/16 00:50

今天来看看Android的MVP模式,使用框架开发,开发速度以及代码的目录结构会别有一番风格。

Google的demo:https://github.com/googlesamples/android-architecture

目前已经完成的示例有
todo-mvp(mvp基础架构示例)

todo-mvp-loaders(基于mvp基础架构项目,获取数据部分使用了Loaders架构)

todo-mvp-databinding(基于mvp基础架构项目,使用了数据绑定组件)

todo-mvp-clean(基于mvp基础架构项目,使用了clean架构的概念)

todo-mvp-dagger(基于mvp基础架构项目,使用了dagger2进行依赖注入)

一张网上的图了解MVP:


这种分层的好处:层与层之间的耦合性低,模块的复用性高,可维护性更好,每层可以单独存在,这样可测性更好

model为上层提供数据,model处理上层传递的数据

presenter是处于mvp的中间层,在view和model中起一个承上启下的作用。presenter会把view交给自己的命令进行一定的校验等操作交给model处理,会把model处理的结果交给view,presenter会根据获取的数据成功与否来通知view应该是显示成功界面还是失败界面。

view就是用户直接看到的界面,一个view可以同时拥有多个presenter,也可以只有一个presenter。
Android中的Activity,Fragment在mvp中是作为view来使用的,各种Adapter是放在view层的。

以下就以登陆界面看看怎么使用MVP结构,先看看一般的(新手)登陆写法

import android.os.Bundle;import android.app.Activity;import android.view.Menu;import android.view.View;import android.widget.Button;import android.widget.EditText;public class LoginActivity extends Activity {private EditText  mUserName, mPassword;    @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_login);initView();}private void initView() {// findViewById.....}/** * 登陆按钮,需要验证输入的数据合法性 * @param view */public void loginCheck(View view){ String userName = mUserName.getText().toString();         String password = mPassword.getText().toString();         //验证用户输入的密码是否合法         if(!validate(userName) || !validate(password)){         //告诉用户输入的用户名或密码不合法         }  else{             //开始登陆             login(userName,password);         }}/** * 访问网络进行登陆,分登陆成功和失败,显示不同的界面 * @param userName * @param password */private void login(String userName, String password) {}/** * 验证数据的合法性 非空等等 * @param userName * @return */private boolean validate(String userName) {// TODO Auto-generated method stubreturn false;}}
这种写法不是不可以,而是所有的功能都写在了一起,耦合性太高,然后可能还会狡辩,你看我所有功能都分方法了,方法分的多清楚...不说了,看看使用MVP来代码重构


从model层开始 ,LoginModel 使用 enum 做一个单例

import java.io.UnsupportedEncodingException;import org.apache.http.entity.StringEntity;import android.util.Log;import com.example.login_mvp.model.interfaces.HttpListener;import com.lidroid.xutils.HttpUtils;import com.lidroid.xutils.exception.HttpException;import com.lidroid.xutils.http.RequestParams;import com.lidroid.xutils.http.ResponseInfo;import com.lidroid.xutils.http.callback.RequestCallBack;import com.lidroid.xutils.http.client.HttpRequest.HttpMethod;/** * 联网获取数据,使用xUtil工具 * enum  实现单例 * @author chenling0418 * */public enum LoginModel {/** enum 实现单例     * 定义一个枚举的元素,它就代表了LoginModel的一个实例。     */INSTANCE;/** 登陆 * @param name 姓名 * @param password 密码 * @param loginListener 登陆结果的回调 */public void login(String name,String password,final HttpListener loginListener){// 使用xUtil ,HttpUtils也应该只有一个实例,这里是模拟HttpUtils httpUtils = new HttpUtils();RequestParams requestParams = new RequestParams();// 建议使用 JSON交互   JsonObjecttry {requestParams.setBodyEntity(new StringEntity("your params"));} catch (UnsupportedEncodingException e) {e.printStackTrace();Log.i("slack", "error:"+e.toString());}// send(HttpMethod method, String url, RequestParams params, RequestCallBack<Object> callBack)httpUtils.send(HttpMethod.POST, "your webservice host", requestParams, new RequestCallBack<String>() {@Overridepublic void onFailure(HttpException arg0, String error) {// TODO Auto-generated method stubif(loginListener != null){loginListener.onFailure(error);}}@Overridepublic void onSuccess(ResponseInfo<String> result) {// TODO Auto-generated method stubif(loginListener != null){loginListener.onSuccess(result.result);}}});}}
接着是Presenter ,LoginPresenter

import com.example.login_mvp.model.LoginModel;import com.example.login_mvp.model.bean.UserInfo;import com.example.login_mvp.model.interfaces.HttpListener;import com.example.login_mvp.presenter.interfaces.ILoginPresenter;import com.example.login_mvp.view.interfaces.ILoginView;/** * 登录的 具体的presenter,负责协调 view 和 model  * presenter 会有多个,负责不同功能 * @author chenling0418 * */public class LoginPresenter implements ILoginPresenter{private ILoginView mLoginView;@Overridepublic void init(ILoginView view) {mLoginView = view;mLoginView.initView();//初始化view(findById...),此处其实是回调}@Overridepublic void login(String name, String password) {//验证name,password的合法性,        if(validate(name) && validate(password)){        // 获取单例        LoginModel.INSTANCE.login(name, password, new HttpListener() {@Overridepublic void onSuccess(String result) {// 这里假设成功后返回的是用户的信息(json) 需要对result处理然后传入 onShowSuccessLoginViewUserInfo userInfo = new UserInfo();//下面的代码在ui线程中执行,这就不写具体的实现了                    mLoginView.onShowSuccessLoginView(userInfo);                    mLoginView.dissLoginingView();}@Overridepublic void onFailure(String error) {//下面的代码在ui线程中执行,这就不写具体的实现了mLoginView.onShowFailedLoginView();mLoginView.dissLoginingView();}});        }else{        //假设1代表账号,密码不合法            mLoginView.onShowLoginCheckErrorView();        }}/** * 验证数据的合法性 非空等等 * @param userName * @return */private boolean validate(String userName) {// TODO Auto-generated method stubreturn false;}@Overridepublic void onStop() {// TODO Auto-generated method stub}@Overridepublic void onResume() {// TODO Auto-generated method stub}@Overridepublic void onDestroy() {// TODO Auto-generated method stub}@Overridepublic void onPause() {// TODO Auto-generated method stub}@Overridepublic void onStart() {// TODO Auto-generated method stub}}
View 层,这里做一个基类BaseActivity

import java.util.HashSet;import java.util.Set;import com.example.login_mvp.presenter.interfaces.IPresenter;import android.content.Intent;import android.os.Bundle;import android.support.v4.app.FragmentActivity;/** * BaseActivity 所有Activity的基类 *  * @author chenling0418 *  */public abstract class BaseActivity extends FragmentActivity {private Set<IPresenter> mAllPresenters = new HashSet<IPresenter>();/** * * 获取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) {}/** * 此处是把所有的presenter 添加到  mAllPresenters 集合 *  * 这里用到了设计模式里的 观察者模式,对象之间的一对多的依赖,这样一来,当一个对象改变时, * 它的所有的依赖者都会收到通知并自动更新 *  */private void addPresenters() {IPresenter[] presenters = getPresenters();if (presenters != null) {for (int i = 0; i < presenters.length; i++) {mAllPresenters.add(presenters[i]);}}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(getLayoutResId());if (getIntent() != null) {parseArgumentsFromIntent(getIntent());}addPresenters();onInitPresenters();}@Overrideprotected void onResume() {super.onResume();// 依次调用IPresenter的onResume方法for (IPresenter presenter : mAllPresenters) {if (presenter != null) {presenter.onResume();}}}@Overrideprotected void onDestroy() {super.onDestroy();// 依次调用IPresenter的onResume方法for (IPresenter presenter : mAllPresenters) {if (presenter != null) {presenter.onDestroy();}}}// ...其他生命周期方法也是类似,调用IPresenter中相应的生命周期方法...}

具体的实现的类

import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import com.example.login_mvp.R;import com.example.login_mvp.model.bean.UserInfo;import com.example.login_mvp.presenter.LoginPresenter;import com.example.login_mvp.presenter.interfaces.IPresenter;import com.example.login_mvp.view.interfaces.ILoginView;/** * view 只专心负责各种 显示 *  * @author chenling0418 * */public class LoginActivity extends BaseActivity implements ILoginView{private LoginPresenter mLoginPresenter = new LoginPresenter();private EditText  mUserName, mPassword;private Button mLogin;   @Overridepublic void initView() {//  ...初始化view的代码... findViewById...mLogin = (Button)findViewById(R.id.login);        mLogin.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubmLoginPresenter.login(mUserName.getText().toString(), mPassword.getText().toString());}});}@Overridepublic void onShowSuccessLoginView(UserInfo userInfo) {// ....显示登录成功界面....}@Overridepublic void onShowFailedLoginView() {// ...显示登录失败界面...}@Overridepublic void showLoginingView() {// ...显示登录进度条对话框...}@Overridepublic void dissLoginingView() {//  ...消失登录进度条对话框...}@Overrideprotected int getLayoutResId() {return R.layout.activity_login;}@Overrideprotected IPresenter[] getPresenters() {return new IPresenter[]{ mLoginPresenter};}@Overrideprotected void onInitPresenters() {mLoginPresenter.init(this);}@Overridepublic void onShowLoginCheckErrorView() {//  ...显示填入信息错误界面...}}
我只能表示看懂了,代码里有注释


参考:http://android.jobbole.com/83294/#rd(特别感谢作者的无私奉献)

GitHub: https://github.com/CL-window/mvpTest/





0 0
原创粉丝点击