认识GOOGLE官方架构MVP
- MVP框架简述
- MVP框架分析
- 实战示范
- 参考内容
MVP框架简述
MVP由model–view–controller (MVC)软件模式衍生而来,是一个把view从底层分离出来的一种轻量模型。
M(model)代表的是将会显示在view(UI)中的数据。
V(view)是显示数据(model)并且将用户指令(events)传送到presenter以便作用于那些数据的一个接口。View通常含有Presenter的引用。
P(presenter)起到控制的作用,是一个中转元素(如 MVC中的controller),且presenter同时引用view和model。
MVP框架分析
- Presenter解耦
Presenter起到的就是转发和控制的作用,如果采用传统的OnClickListener监听来代替Presenter,则无法对View内部元素进行合理的控制,控制逻辑复杂。而Presenter了解View的内部结构,可以有效地进行控制,并保证低耦合。
加之,Presenter不应被绑定到Android平台,Presenter的内容应该是普遍意义上能与其他任何java应用共享的java代码。 - View自主权
View只执行Presenter指示的操作,即完全依靠Presenter的控制进行工作,所以在进行接口设计时,应该让Presenter控制View的方式更加抽象,粒度不能够太小。
类图及分析如下
- BaseView
界面需要提供的方法中会有很多类似的,把它们提取到一个公共的父类接口中。比如setPresenter方法,其他的view层接口就可以直接继承BaseView接口,不必做重复工作。
public interface BaseView<T> {
void setPresenter(T presenter);
}
- BasePresenter
同理,BasePresenter提供重复的Presenter接口。
public interface BasePresenter {
void start();
}
- Contract
工程中,每一个模块都有一个自己的Contract接口,Contract包涵了Presenter和View,Presenter实现的逻辑层方法,View实现的界面层的方法都能在Contract接口中一目了然的看明白,具体的Presenter和View的实现类都是通过实现Contract接口来完成。这种管理办法使得开发和维护十分简单。
public interface XXXContract {
interface View extends BaseView<Presenter> {
}
}
interface Presenter extends BasePresenter {
}
}
实战示范
项目目录
注:实例来自笔者亲身参与的一款运动体验项目
项目结构的组织方式基本按照功能进行划分,之后我们具体关注login模块中MVP的实现用于理解MVP的实现流程。
- LoginContract
具体login任务的Presener和View接口,Presenter接口里面封装的是数据获取的方法,需要数据提供者具体实现;View里面封装是界面层(Fragment)要实现的方法。
public interface LoginContract {
interface View extends BaseView<Presenter> {
/**
* 设置加载提示符
*/
void showLoadingIndicator();
/**
* 设置出错信息
*/
void showErrorInfo();
}
interface Presenter extends BasePresenter {
boolean checkAccount(String username, String password);
}
}
- LoginPresenter
继承LoginContract.Presenter接口,实现具体的功能方法,代码不再赘述。 - LoginActivity
在MVP架构中,个人理解Activity主要负责控制,Fragment负责展示,当然MVP只是一种思想,代码书写的方式因人而异。
LoginActivity的主要只能有初始化Fragment并创建Presenter。
public class LoginActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login_act);
LoginFragment loginFragment = (LoginFragment) getSupportFragmentManager().findFragmentById(R.id.layout_login_content);
if (loginFragment == null) {
loginFragment = loginFragment.newInstance(); ActivityUtils.addFragmentToActivity(getSupportFragmentManager(), loginFragment, R.id.layout_login_content);
}
new LoginPresenter(loginFragment);
}
}
- LoginFragment
LoginFragment是View接口的实现类,其不与Model层进行交互,只和presenter的实例进行交互。
LoginFragment持有相应LoginPresenter的引用,通过view的setPresenter方法完成实例的关联操作。当LoginFragment收到界面操作请求即通过LoginPresenter完成逻辑上的处理。
public class LoginFragment extends Fragment implements LoginContract.View {
private LoginContract.Presenter mPresenter;
private EditText edtTxt_userName;
private EditText edtTxt_passWord;
private Button btn_login;
private Button btn_noAccount;
public static LoginFragment newInstance() {
return new LoginFragment();
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.login_frag, container, false);
return root;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
btn_login = (Button) getActivity().findViewById(R.id.btn_login);
btn_noAccount = (Button) getActivity().findViewById(R.id.btn_noAccount);
edtTxt_userName = (EditText) getActivity().findViewById(R.id.edtTxt_userName);
edtTxt_passWord = (EditText) getActivity().findViewById(R.id.edtTxt_passWord);
btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean loginResult = mPresenter.checkAccount(edtTxt_userName.getText().toString(), edtTxt_passWord.getText().toString());
if (loginResult) {
getActivity().finish();
Intent intent = new Intent(getActivity(), HomePageActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
}
});
btn_noAccount.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), RegisterActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
});
}
@Override
public void onResume() {
super.onResume();
mPresenter.start();
}
@Override
public void onStop() {
super.onStop();
edtTxt_userName.setText("");
edtTxt_passWord.setText("");
}
@Override
public void showLoadingIndicator() {
Toast.makeText(getActivity().getApplicationContext(), "登录成功",Toast.LENGTH_SHORT).show();
}
@Override
public void showErrorInfo() {
Toast.makeText(getActivity().getApplicationContext(), "用户名或密码错误",Toast.LENGTH_SHORT).show();
}
@Override
public void setPresenter(LoginContract.Presenter presenter) {
mPresenter = presenter;
}
}