andorid 中 MVP模式 个人理解与运用(原创)
2015-08-05 12:00
120 查看
andorid 中 MVP模式 个人理解与运用(原创)
原创文章,转载请注明出处!by–臻宇
前几天阅读了关于MVC模式和MVP模式的文章,文章链接如下:
http://www.uml.org.cn/sjms/201006244.asp
笔者觉得很有意思,于是便想尝试对MVP模式的运用,笔者为了突出MVP模式的重点“怎么将数据(data)从用户接口(view)中分离出来,以及用户接口如何与数据进行交互”简化了一些代码逻辑,望大家不要介意,这里运用的情景是登录,我将尝试着运用MVP模式对登录情景将登录界面(View)与登录逻辑(Model)进行分离,他们通过Presenter进行交互。
界面如图所示:
既然是MVP模式的运用,自然少不了M(Model),V(View),P(Presenter)这三者:
/** * Model 主要任务是处理业务 * Created by Administrator on 2015/8/4. */ public interface LoginModel <T>{ /** * 处理登录 * @param name * @param password * @return */ public T login(String name,String password); }
/** * 视图,只要任务在于更新视图 * Created by Administrator on 2015/8/4. */ public interface LoginView <T> { public void showPreExecute();//更新马上登录前的UI变化,比如添加缓冲条什么的。。 public void showResult(T data);//将结果更新到UI上 public void showProgress(Integer progress);//更新进度 }
/** * 控制者 Presenter * Created by Administrator on 2015/8/4. */ public class Presenter extends AsyncTask<String, Integer, String> { //模型对象 private LoginModel<Boolean> loginModel; //视图对象 private LoginView<String> loginView; public Presenter(LoginView<String> loginView) { this.loginModel = new LoginTask(); //LoginTask是LoginModel的实现类 this.loginView = loginView; //一般是Activity或者Fragment } @Override protected String doInBackground(String... params) { //做了些逻辑处理 if(TextUtils.isEmpty(params[0]) || TextUtils.isEmpty(params[1])) { return "用户名或密码不能为空"; } if(params[0].length()<6 ||params[0].length()>32) { return "用户名不合法"; } if(params[1].length()<6 ||params[1].length()>32) { return "密码长度不合法"; } //吧啦吧啦。。。 // 比如判断网络,检查用户名类型什么之类的一大堆逻辑, //........... //整个登录判断逻辑走完了,接下来正式登录了 for(int i=0;i<100;i++) //模拟更新进度 { try { publishProgress(i);// Thread.sleep(200); }catch(InterruptedException e) { return "登录异常!"; } } Boolean result = loginModel.login(params[0], params[1]);//模拟登录处理 if(result) return "登录成功"; else return "登录失败"; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); loginView.showProgress(values[0]);//将新进度更新到UI上 } @Override protected void onPostExecute(final String success) { loginView.showResult(success);//业务处理好了,更新视图 } @Override protected void onPreExecute() { super.onPreExecute(); if(loginView != null) loginView.showPreExecute();//更新登录前的UI } }
对于Presenter,笔者只是简单地继承于AsyncTask,目的就是为了做耗时操作,可以看到,在Presenter内部做了许多逻辑处理,如果这些代码放到Actvity中,就会导致代码可读性下降了,处理了业务逻辑后,
Presenter就简单地调用了loginModel进行业务处理,而并不关心loginModel如何处理登录,然后拿到处理结果并通过调用loginView去更新视图,而并不关心loginView如何更新视图。
而且可以很清楚地看到,loginModel与loginView并没有调用或者引用关系,也就是说二者实现了解耦,完全通过Presenter控制二者的交互,应该是符合MVP模式的思想了吧。
接下来再看看,视图与模型的具体实现类吧:
/** * 模型的实现类 处理登录请求 * Created by Administrator on 2015/8/4. */ public class LoginTask implements LoginModel<Boolean> { String mEmail; String mPassword; @Override public Boolean login(String name, String password) { //...耗时的网络请求 //假定登录失败 Boolean result = false ; return result; } }
这个很简单吧,就是做些网络请求之类的,然后返回数据!
/** * 这里Activity实现了LoginView接口,所以充当视图,其代码很简单,就是更新视图 * 这个界面不是笔者写的,只是照搬谷歌的模板。 */ public class LoginActivity extends Activity implements LoginView<String> { // UI private AutoCompleteTextView nameView; private EditText mPasswordView; private ProgressBar mProgressView; private View mEmailLoginFormView; private View mSignOutButtons; private View mLoginFormView; Toast toast; Presenter presenter; //控制者 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); nameView = (AutoCompleteTextView) findViewById(R.id.username); mPasswordView = (EditText) findViewById(R.id.password); Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button); mEmailSignInButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { String name =nameView.getText().toString(); //从UI上获取用户输入 String psw = mPasswordView.getText().toString(); presenter = new Presenter(LoginActivity.this);//创建一个控制者 presenter.execute(name,psw); //将数据提交给presenter,让presenter去处理 } }); mLoginFormView = findViewById(R.id.login_form); mProgressView = (ProgressBar)findViewById(R.id.login_progress); mEmailLoginFormView = findViewById(R.id.email_login_form); mSignOutButtons = findViewById(R.id.plus_sign_out_buttons); } @Override public void showPreExecute() { showToast("开始请求登录"); mProgressView.setVisibility(View.VISIBLE); } @Override public void showResult(String data) { mProgressView.setVisibility(View.GONE); showToast(data); } @Override public void showProgress(Integer progress) { mProgressView.setProgress(progress); } void showToast(String s) { if(toast!=null )toast.cancel(); toast = Toast.makeText(this,s,Toast.LENGTH_SHORT); toast.show(); } }
作为一个Actvity,其代码量是很少了吧。可以看到,这个Actvity只做了大致做了三件事: 1.初始化UI; 2.从UI上提取用户输入,并提交给Presenter; 3.被动地更新UI。
所以整个逻辑是很清晰的,作为一个视图,它就负责UI!其实,它也可以是Fragemnt,也可以是别的什么布局,反正就是更新UI,对不,这就是MVP模式的好处啊,改天,我想改变一下进度条的显示效果,或者登陆成后弹出个窗口之类的,可以具体定位到具体的方法里改就好,不需在一大堆逻辑与UI混杂的代码里艰涩的修改。对于Model来说,修改业务代码也是如此。
我这个demo大致就这样了,XML代码很简单,我就不贴出来了,这就是我对MVP模式的理解与运用,也许还有理解不到位的地方,希望大家指出!
另外,这个demo只是为了凸显MVP模式的优点,有些细节并没有处理好,例如使用AsyncTask导致的内存泄露的问题等,请谅解啦!
相关文章推荐
- linux结束进程步骤
- 刚进入页面时UIScrollView没有滑动到顶部
- iOS 使用AFNetworking框架检测当前网络连接状态
- MSDN——Library库
- 刚进入页面时UIScrollView没有滑动到顶部
- 初学git:用git bash往github push代码
- 初学git:用git bash往github push代码
- Git 使用规范流程
- iOS 判断身份证号码
- UIAlertController
- CC2541 设备发送数据给手机
- test
- poj 3907 求多边形面积
- TCP的流量控制与拥塞控制的对比
- 日期的实现与获取
- 初学git:用git bash往github push代码
- Hibernate多对多双向关联(xml配置)
- [转]uri vs url vs urn
- swift之函数式编程(五)
- jquery ajax请求成功,数据返回成功,seccess不执行的问题