多日未回博客園,風蕭蕭兮易水寒。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(測試驅動開發)就能更好的實施了,咱們能在後臺未完成的時候很快捷的模擬出本身想要的數據,從而讓咱們進度不被滯後。
【世界盃要決賽了,買什麼?】