android MVP 開發模式的理解
在進入MVP介紹前。我們先來看一下一直沿用的MVC的開發的模式。
明人一看上面的結構圖就知道MVC中是允許Model 和 View 進行交互的。
每種模式都有利與弊,不能說那種模式好與不好。爲了“高內聚,低耦合”的思想。個人覺得MVP更能體現之特性。
下面讓我們來看看MVP的結構圖:
View對應於activity,負責View的繪製以及用戶的交互,理應做到View是最薄的一層,利於UI重新設計與變更。 Model 數據源與實體模型。比如,保存到本地的數據。數據庫的數據。網絡請求回來的數據。 Presenter 負責View與Model的交互。起到一箇中間的角色。說白了就是個控制器。由它來控UI的數據來源和UI顯示。
- 如果理解這三個概念。接下來就說說代碼結構吧。
代碼分塊。這並不是MVP的主旨。可以根據個人愛好來分。最重要的是我們在寫代碼時,如何運用MVP的思維。做到代碼清淅明瞭,維護性高。邏輯簡單明瞭。
接下來看一個簡單的例子。如
/** * Created by cc on 16/4/13. */ public interface ILoginView { String getPhone(); String getPassWord(); void setPhone(String phone); void setPassWroid(String passWroid); void startIndexActivity(); void startForgetActivity(); Context getContext(); void promptToastMessge(String msg); void showProgressBar(String msg); void setProgressBarMessage(String msg); void hideProgressBar(); }
/** * Created by cc on 16/4/13. */ public interface ILoginMode { void onSuccess(Object object); void onFail(Object object); }
/** * Created by cc on 16/4/13. */ public class LoginService { public LoginService(final ILoginMode iLoginMode) { //這裏模擬網絡請求。按道理來說。這裏不該出現os包的代碼。這裏只爲了測試。 // 建設 model層。放在異步線程執行。可以試一下 //Rx(rxjava或rxandroid) 與 Retrogit //Rx(rxjava或rxandroid) 可以簡單理解爲"異步" //Retrogit網絡請求 new Handler().postDelayed(new Runnable() { @Override public void run() { //模擬加載數據 if (new Random().nextBoolean()){ iLoginMode.onSuccess("請求成功"); return; } iLoginMode.onFail("請求失敗"); } },3000); } }
/** * Created by cc on 16/4/13. */ public class LoginPresenter { private ILoginView mILoginView; public LoginPresenter(ILoginView iLoginView) { mILoginView = iLoginView; } public void onCreate() { LocalLoginPhone localLoginPhone = new LocalLoginPhone(); String phone = localLoginPhone.getLoginPhone(mILoginView.getContext()); mILoginView.setPhone(phone); } public void deletePhoneClick() { mILoginView.setPhone(""); } public void deletePassWordClick() { mILoginView.setPassWroid(""); } public void forgetPassWordClick() { mILoginView.startForgetActivity(); } public void LoginClick() { String phone = mILoginView.getPhone(); if (TextUtils.isEmpty(phone)) { mILoginView.promptToastMessge("填寫信息有誤"); return; } String possWord = mILoginView.getPassWord(); if (TextUtils.isEmpty(possWord)) { mILoginView.promptToastMessge("填寫信息有誤"); return; } mILoginView.showProgressBar("正在加載"); LoginService loginService = new LoginService(new ILoginMode() { @Override public void onSuccess(Object object) { mILoginView.setProgressBarMessage(object.toString()); mILoginView.hideProgressBar(); mILoginView.startIndexActivity(); } @Override public void onFail(Object object) { mILoginView.setProgressBarMessage(object.toString()); mILoginView.hideProgressBar(); mILoginView.promptToastMessge("提交失敗"); } }); } }
/** * Created by cc on 16/4/13. */ public class LogInActivity extends BaseActivity implements ILoginView { private EditText login_et_phone, login_et_password; private Button login_btn_delete_phone, login_btn_delete_password, login_btn_login, login_btn_forget_password; private LoginPresenter mLoginPresenter; private LittleDialog mDialog; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.act_login); initView(); mLoginPresenter = new LoginPresenter(this); mLoginPresenter.onCreate(); } private void initView() { login_et_phone = (EditText) findViewById(R.id.login_et_phone); login_et_password = (EditText) findViewById(R.id.login_et_password); login_btn_delete_phone = (Button) findViewById(R.id.login_btn_delete_phone); login_btn_delete_password = (Button) findViewById(R.id.login_btn_delete_password); login_btn_login = (Button) findViewById(R.id.login_btn_login); login_btn_forget_password = (Button) findViewById(R.id.login_btn_forget_password); login_btn_delete_phone.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mLoginPresenter.deletePhoneClick(); } }); login_btn_delete_password.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mLoginPresenter.deletePassWordClick(); } }); login_btn_login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mLoginPresenter.LoginClick(); } }); login_btn_forget_password.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mLoginPresenter.forgetPassWordClick(); } }); } @Override public String getPhone() { return login_et_phone.getText().toString().trim(); } @Override public String getPassWord() { return login_et_password.getText().toString().trim(); } @Override public void setPhone(String phone) { login_et_phone.setText(phone); } @Override public void setPassWroid(String passWroid) { login_et_password.setText(passWroid); } @Override public void startIndexActivity() { UIHelper.startActivity(this, IndexActivity.class, null); } @Override public void startForgetActivity() { } @Override public Context getContext() { return this; } @Override public void promptToastMessge(String msg) { Toast.makeText(this, msg, Toast.LENGTH_LONG).show(); } @Override public void showProgressBar(String msg) { mDialog = new LittleDialog(this, msg); mDialog.show(); } @Override public void setProgressBarMessage(String msg) { if (null != mDialog) mDialog.setMessage(msg); } @Override public void hideProgressBar() { if (null != mDialog) mDialog.dismiss(); } }
/** * UI操作輔助類 * @author alafighting 2016-0 */ public class UIHelper { /** * 界面跳轉 * @param context * @param activity * @param bundle */ public static void startActivity(Context context, Class<? extends Activity> activity, Bundle bundle) { if (context == null) { throw new NullPointerException("context不能爲空"); } Intent intent = new Intent(context, activity); if (null !=bundle){ intent.putExtras(bundle); } context.startActivity(intent); } /** * 打開主界面 * @param context */ public static void startMain(Context context) { startActivity(context, IndexActivity.class,null); } }
/** * Created by cc on 16/4/13. */ public class BaseActivity extends AppCompatActivity { public Context getContext() { return super.getApplicationContext(); } public Activity getActivity() { return this; } public <T extends android.support.v4.app.Fragment> T findSupportFragment(Class<T> fragmentClass) { android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager(); android.support.v4.app.Fragment fragment = fragmentManager.findFragmentByTag(fragmentClass.getName()); return (T) fragment; } public <T extends android.support.v4.app.Fragment> T newSupportFragment(Class<T> fragmentClass, Bundle args) { android.support.v4.app.Fragment fragment = android.support.v4.app.Fragment.instantiate(getContext(), fragmentClass.getName(), args); fragment.setArguments(args); return (T) fragment; } }
上面的例子是不是看起來很明瞭。關鍵問題,大家看到這代碼後,會認爲這只是把邏輯代碼模塊的東西放到一另一個類而已。如果你這麼理解。說明你對寫代碼的一個整體認識觀不是很有藝術。人人都說寫代碼是一門藝術。
上面的代碼結構還是有好處的。如,當測試跟你說這接口請求出錯了。出bug了。這時平常我們會去找到這個接口在那個activity裏調用。在那一行代碼裏。聰明的人可能不會這麼幹。或許習慣自已寫測試用例時,只需調用LoginService實現ILoginModel接口就好了,就可以知道自已有沒有搞錯了。是不是很 66666
最後說一個mvp 的優點
MVP的優點:
模型與視圖完全分離,我們可以修改視圖而不影響模型
可以更高效地使用模型,因爲所有的交互都發生在一個地方——Presenter內部
我們可以將一個Presenter用於多個視圖,而不需要改變Presenter的邏輯。這個特性非 常的有用,因爲視圖的變化總是比模型的變化頻繁。
如果我們把邏輯放在Presenter中,那麼我們就可以脫離用戶接口來測試這些邏輯(單 元測試)
說明。上面有一兩張圖是截網上的。如果有侵權,請及時聯繫我刪除,謝謝。
在此感謝以上幾個人。老八,殼,替補,roy,朽木,在我理解MVP 過程中。他們給予我解答