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 过程中。他们给予我解答