多日未回博客园,风萧萧兮易水寒。android
话说上一次发表随笔已经是去年,并且看看当时关于android视频方面的记录也只写了开篇就自动阉割成了太监,究其原因已不堪回首。服务器
太监终究仍是太监,不必再为它续弦。网络
笔锋一转,近日有看几本android应用方面优化和技巧方面的书,便以为又该在此处记录下了。有一本专门讲技巧的书还不错,《50 Android Hacks》:50个android开发诀窍。数据结构
其中有一篇是讲MVP(Model-View-Presenter)模式的,也就是模型-视图-主导器(书中翻译为此)。app
我大概理解了下该篇内容,以几乎能够和HELLO WORLD 齐名的登录功能为需求,写了个Demo,以明了其中的原因,若是如下内容有出错的地方,还望指正,不吝赐教。ide
【一笔带过】MVP模式与大名鼎鼎的MVC模式彷佛就只有最后一个字母的差异,也就在于主导器代替了控制器的地位。所谓主导器,也就是扮演着主导一切(模型与视图)的地位。测试
【先看看咱们熟悉的】模型层,一般是数据结构,咱们业务须要用到的一些数据封装。这里会稍稍有些不一样,咱们同时封装了数据行为,便是该类具备咱们实际业务逻辑的要实现的方法。--一小波代码正在袭来...优化
1 package com.change.mvpdemo.modle; 2 3 /** 4 * MVP模式的m(模型)层。 5 * 登录状态,登录的实际逻辑实现它去完成。 6 * @author Change 7 * 8 */ 9 public interface ILoginStatus extends IStatus{ 10 public static final int STATUS_VERIFY_FAIL = -1;//验证失败 11 public static final int STATUS_LOGIN_FAIL = -2;//登录失败 12 public static final int STATUS_LOGIN_SUCCESS = 0;//登录成功 13 public static final int STATUS_LOGIN_ING = 1;//登录中 14 /** 15 * 登录行为 16 * @param account 17 * @param psw 18 * @return 状态码 19 */ 20 public void login(String account,String psw,IStatusCallback callback); 21 }
【简单说说】我有个接口IStatus暂时来讲没什么内容,或许能够放一些共有的状态,好比响应成功或者失败。而后数据模型以状态的形式存在,由于我有个不怎么成熟的想法就是数据每每都是根据业务状态在修改它自己的内容。而后就一个login()方法,里面的参数有请求和响应。好吧,是时候去实现它了--》this
package com.change.mvpdemo.modle.impl; import android.os.AsyncTask; import android.text.TextUtils; import com.change.mvpdemo.modle.ILoginStatus; import com.change.mvpdemo.modle.IStatusCallback; /** * 实现类,真正的数据访问在这里。 * * @author Change */ public class LoginStatus implements ILoginStatus { private int status = ILoginStatus.STATUS_LOGIN_ING; private String msg = ""; @Override public void login(final String account, final String psw, final IStatusCallback callback) { new AsyncTask<String, Void, ILoginStatus>() { @Override protected ILoginStatus doInBackground(String... arg0) { if (varify(account, psw)) { try {//模拟网络请求耗时处理 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } if ("Change".equals(account) && "123".equals(psw)) { status = ILoginStatus.STATUS_LOGIN_SUCCESS; msg = "登录成功"; } else { status = ILoginStatus.STATUS_LOGIN_FAIL; msg = "登录失败"; } } return LoginStatus.this; } @Override protected void onPreExecute() { callback.onStatus(LoginStatus.this); } @Override protected void onPostExecute(ILoginStatus result) { callback.onStatus(result); } }.execute(); } /** * 本地校验 * * @param account * @param psw * @return */ private boolean varify(String account, String psw) { if (TextUtils.isEmpty(account)) { status = ILoginStatus.STATUS_VERIFY_FAIL; msg = "用户名不能为空!"; return false; } if (TextUtils.isEmpty(psw)) { status = ILoginStatus.STATUS_VERIFY_FAIL; msg = "密码不能为空!"; return false; } return true; } public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
【简单说说】这是个人数据模型,我有状态(status),要反馈给视图的信息(msg)。里面有本地验证方法varify()和提交服务器(此处只是模拟个耗时)login()方法的实现。根据login方法的反馈修改自身并回调。咱们该关心是谁在实现这个回调了--》spa
【再看看咱们熟悉的】视图层,万恶的视图永远都占据着用户的眼球,好吧,全部后台偷偷摸摸完成的东西都要拿出来晾晾了。--》
package com.change.mvpdemo.view; /** * MVP模式的V(视图)层 * 这是一个抽象的登录视图,里面都是一些界面动做,想要执行这些动做的界面都会去实现它。 * @author Change * */ public interface ILoginView extends IView{ /** * 弹出提示信息。 */ public void showMsg(String msg); /** * 成功登录跳转主页。 */ public void moveToMain(); /** * 加载中,万恶的菊花。 */ public void showLoadding(); /** * 隐藏菊花。 */ public void hideLoadding(); }
【简单说说】不管是亲切的hello world(主页)跳转,仍是万恶的菊花,仍是该死的提示。ILoginView一手包办。来吧,让UI交互来的更猛烈些吧。
【咱们最为熟悉的】activity君隆重登场,它会绝不留情的实现ILoginView。而且将UI蹂躏的七零八落。
1 package com.change.mvpdemo.view.impl; 2 3 import android.app.Activity; 4 import android.app.ProgressDialog; 5 import android.content.Intent; 6 import android.os.Bundle; 7 import android.view.View; 8 import android.view.View.OnClickListener; 9 import android.widget.Button; 10 import android.widget.EditText; 11 import android.widget.Toast; 12 13 import com.change.mvpdemo.R; 14 import com.change.mvpdemo.presenter.LoginPersenter; 15 import com.change.mvpdemo.view.ILoginView; 16 17 /** 18 * 个人的activity,实现view抽象类,得到动做。 19 * 20 * @author Change 21 * 22 */ 23 public class LoginActivity extends Activity implements ILoginView, 24 OnClickListener { 25 private ProgressDialog dialog; 26 private EditText etAccount, etPsw; 27 private Button btnLogin; 28 private LoginPersenter mPersenter; 29 30 @Override 31 protected void onCreate(Bundle savedInstanceState) { 32 super.onCreate(savedInstanceState); 33 setContentView(R.layout.activity_login); 34 mPersenter = new LoginPersenter(); 35 mPersenter.setLoginPersenterView(this); 36 initViews(); 37 } 38 39 @Override 40 public void showMsg(String msg) { 41 Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); 42 } 43 44 @Override 45 public void moveToMain() { 46 Intent toMain = new Intent(this, MainActivity.class); 47 startActivity(toMain); 48 } 49 50 @Override 51 public void showLoadding() { 52 dialog.show(); 53 } 54 55 @Override 56 public void hideLoadding() { 57 dialog.cancel(); 58 } 59 60 @Override 61 public void initViews() { 62 dialog = new ProgressDialog(this); 63 dialog.setMessage("加载中。。。"); 64 etAccount = (EditText) findViewById(R.id.et_account); 65 etPsw = (EditText) findViewById(R.id.et_psw); 66 btnLogin = (Button) findViewById(R.id.btn_login); 67 btnLogin.setOnClickListener(this); 68 } 69 70 @Override 71 public void onClick(View arg0) { 72 switch (arg0.getId()) { 73 case R.id.btn_login: 74 mPersenter.didLoginSuccess(etAccount.getText().toString(), etPsw 75 .getText().toString()); 76 break; 77 78 default: 79 break; 80 } 81 } 82 83 }
【主导器君隆重登场】我想诸位都已经看到这厮了-_-|||-->mPersenter,没错,这厮即是个人主导器君。好的,它来了--》
package com.change.mvpdemo.presenter; import com.change.mvpdemo.modle.ILoginStatus; import com.change.mvpdemo.modle.IStatus; import com.change.mvpdemo.modle.IStatusCallback; import com.change.mvpdemo.modle.impl.LoginStatus; import com.change.mvpdemo.view.ILoginView; /** * MVP模式中的P(主导器),它负责主导全部的模型和视图。 * * @author Change * */ public class LoginPersenter { private ILoginView mLoginView;// 持有视图对象 private ILoginStatus mStatus;// 持有模型 public LoginPersenter() { mStatus = new LoginStatus(); } public void setLoginPersenterView(ILoginView _loginView) { this.mLoginView = _loginView; } public ILoginView getLoginPersenterView() { return mLoginView; } public void didLoginSuccess(String account, String psw) { mStatus = new LoginStatus(); mStatus.login(account, psw, new IStatusCallback() { @Override public void onStatus(IStatus status) { LoginStatus s = (LoginStatus) status; switch (s.getStatus()) { case ILoginStatus.STATUS_VERIFY_FAIL:// 验证失败 case ILoginStatus.STATUS_LOGIN_FAIL:// 登录失败 mLoginView.hideLoadding(); mLoginView.showMsg(s.getMsg()); break; case ILoginStatus.STATUS_LOGIN_ING:// 登录中 mLoginView.showLoadding(); break; case ILoginStatus.STATUS_LOGIN_SUCCESS:// 登录成功 mLoginView.hideLoadding(); mLoginView.moveToMain(); break; default: break; } } }); } }
【其实它也不过如此】主导器中我就写了个核心的方法didLoginSuccess(),它主导模型与视图,让视图在根据模型的变化而作出正确的响应。
【该作个总结性的发言了】莱迪森,剑特闷-_-||
【MVP模式有什么用】其实回顾下模式的各个模块,彷佛解耦的很干脆,是的,咱们的视图和模型被瓦解出来了,这个时候咱们的TDD(测试驱动开发)就能更好的实施了,咱们能在后台未完成的时候很快捷的模拟出本身想要的数据,从而让咱们进度不被滞后。
【世界杯要决赛了,买什么?】