Model-view-presenter,简称MVP,是电脑软件设计工程中一种对针对MVC模式,再审议后所延伸提出的一种软件设计模式。java
M-Model,数据层android
V-View,界面显示层git
P-Presenter,中介者,链接Model和View层github
结构图以下:数据库
从图中能够看到,View能够和Presenter进行双向通讯,Presenter和Model进行单方面通讯,而View和Model是不能直接进行通讯的。设计模式
那么这个通讯是什么意思呢?我我的理解就是是否持有对方的实例,是否可以调用对方的方法。服务器
因此,这里就很清晰了。咱们在代码中想要实现这个架构的话,其实也很简单,就是让View和Presenter相互持有以及让Presenter持有Model的对象。网络
咱们用简单的代码演示一下:架构
public class View {
private Presenter presenter;
}
public class Presenter {
private View view;
private Model model;
}
public class model {}复制代码
咱们的示例代码就实现了咱们上面所要求的那些:让View和Presenter双向绑定、让Presenter持有Model的引用。ide
好,到如今,你已经初步了解了MVP的规则(也能够叫作套路)。
有的同窗可能会问,这样写的代码量变多了,为何要这样写?这个咱们后边再讲。
既然已经了解了MVP的基本规则,那么咱们就来看一下如何在Android中实现这个架构。
首先,咱们先要了解一下Android中的M、V、P分别都表明着什么。
在Android中,显示的操做是交给Activity或者Fragment的。因此理所固然的,Activity\Fragment就是MVP中的View了。
既然把Activity或者Fragment看成View层,即显示层,那么它的工做应该就是显示操做,不该该有其余类型的操做,例如解析数据等等。因此你会发现View中的方法大多就是showXXX()
,hideXXX()
等等。
在个人理解中,一切的逻辑操做都应该在Presenter中处理,可是,实际状况中,有些特别小的逻辑也能够在View中直接实现。
这里的Presenter就是处理各类逻辑。例如这样一个场景:从服务器获取数据,对数据进行处理,而后显示在界面上。相信开发者们都遇到过这样的需求。那么在咱们的MVP架构中是如何实现的呢?
流程就和图中显示的同样,Model提供数据、Presenter处理数据、View显示操做
并且命令Model提供数据和命令View显示数据这两个操做都应该在Presenter中进行,因此你会发现,MVP的核心就是Presneter中,其余两个部分都很单一,就像是工具类同样,任人调用。
从这个角度出发的话,Presenter必需要持有Model和View的引用,由于只有这样才能命令它们执行某个操做。
那为何View还要持有Presneter的引用呢?其实缘由很简单,由于在Android中大多数事务都是从View中产生的。例如:你想要添加一条数据,点击了那个+
号按钮,无形中就产生了一个事务。
也就是说不少逻辑都是从View中产生,而后命令Presenter去处理数据(好比检验数据是否合理),再而后Presenter再命令Model添加数据。因此,View中也必须持有Presenter的引用,也就是说View和Presenter相互持有。
Model就很简单了,根据咱们上边的描述,就知道Model就至关于一个包装后的数据库,执行着与数据相关的操做。
另外,我上面说的把Activity、Fragment看成View层只是一种实现方法。还有一种实现方法就是把Activity\Fragment看成Presenter,将UI操做抽到delegate中做为View层(例如T-MVP
)。
接下来咱们就在Android中完完整整地实现MVP架构。
注意在这里咱们采起和Google同样的思路,根据功能进行分包。如图就是个人项目包结构:
SingleFragmentActivity
public abstract class SingleFragmentActivity extends AppCompatActivity {
protected abstract Fragment createFragment();
protected void init() {
}
/** * 能够设置一个只有FrameLayout的xml文件做为默认的Fragment容器, * 若子类有更好的容器能够重写该方法,若没有则能够直接用默认的容器 * 假设布局文件名字为activity_fragment.xml */
@LayoutRes
protected abstract int getLayoutResId();
@IdRes
protected abstract int getFragmentContainerId();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutResId());
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(getFragmentContainerId());
if (null == fragment) {
fragment = createFragment();
fm.beginTransaction()
.add(getFragmentContainerId(), fragment)
.commit();
}
init();
}
}复制代码
BaseView
public interface BaseView<T> {
void setPresenter(T t);
}复制代码
BasePresenter
public interface BasePresenter {
void start();
void destroy();
}复制代码
SignInActivity
public class SignInActivity extends SingleFragmentActivity {
@Override
protected int getLayoutResId() {
return R.layout.sign_in_act;
}
@Override
protected int getFragmentContainerId() {
return R.id.fragment_container;
}
@Override
protected Fragment createFragment() {
return SignInFragment.newInstance();
}
}复制代码
SignInContract
public interface SignInContract {
interface Presenter extends BasePresenter {
void signIn(String username, String passwd, Action<Integer> action);
void signIn(String username, String passwd);
}
interface View extends BaseView<Presenter> {
String getUsername();
String getPasswd();
void showToast(String message);
}
}复制代码
SignInFragment
public class SignInFragment extends Fragment implements SignInContract.View {
private static String TAG = "SignInFragment";
private SignInContract.Presenter mPresenter;
private View rootView;
private EditText mEtUsername;
private EditText mEtPasswd;
private Button mBtnSignIn;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = new SignInPresenter(this,
new ResponseImpl(new LocalResponse(), new RemoteResponse()));
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.sign_in_frag, container, false);
mEtPasswd = (EditText) rootView.findViewById(R.id.et_username);
mEtUsername = (EditText) rootView.findViewById(R.id.et_passwd);
mBtnSignIn = (Button) rootView.findViewById(R.id.btn_sign_in);
initEvent();
return rootView;
}
private void initEvent() {
mBtnSignIn.setOnClickListener(v ->
mPresenter.signIn(getUsername(), getPasswd(),
result_code -> {
if (result_code == 0) {
showToast(getString(R.string.sign_in_success));
} else {
showToast(getString(R.string.sign_in_fail));
}
}));
}
@Override
public void onResume() {
super.onResume();
if (mPresenter != null) {
mPresenter.start();
}
}
@Override
public void onDestroy() {
if (mPresenter != null) {
mPresenter.destroy();
}
super.onDestroy();
}
@Override
public void setPresenter(SignInContract.Presenter presenter) {
mPresenter = presenter;
}
@Override
public String getUsername() {
return mEtUsername.getText().toString();
}
@Override
public String getPasswd() {
return mEtPasswd.getText().toString();
}
@Override
public void showToast(String message) {
Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
}
/** * * @return 返回一个指定的Fragment实例 */
public static Fragment newInstance() {
return new SignInFragment();
}
}复制代码
public class SignInPresenter implements SignInContract.Presenter {
private static String TAG = "SignInPresenter";
private SignInContract.View mView;
private ResponseImpl mResponse;
public SignInPresenter(SignInContract.View view, ResponseImpl response) {
mView = view;
mView.setPresenter(this);
mResponse = response;
}
@Override
public void start() {
Log.i(TAG, "start: ");
}
@Override
public void destroy() {
Log.i(TAG, "destroy: ");
}
@Override
public void signIn(String username, String passwd, Action<Integer> action) {
mResponse.signIn(username, passwd, action);
}
@Override
public void signIn(String username, String passwd) {
mResponse.signIn(username, passwd, integer -> {
if(integer == 0) {
mView.showToast("Success");
} else {
mView.showToast("fail");
}
});
}
}复制代码
限于篇幅,Model的代码咱们就不贴了,你们能够去个人Github上去看完整的demo。
值得注意的地方,咱们的BasePresenter中提供了两个方法start()
和destroy()
,目的就是要把Presenter的生命周期和Fragment的生命周期绑定在一块儿。另外,能够改进的地方是Response的实现类能够改为单例模式,以及为ResponseImpl传入一个Context
参数,因访问数据库操做和访问网络操做都是须要Context
的。
最大的问题就是MVP须要建立太多的接口和实现类。
针对这个问题,有一种解决方法就是使用Android Studio的Template自动生成须要的类和接口,可是这种方法只是解放了双手,并无减小代码量。
另外就是,若是某个界面的逻辑很简单,那么能够直接把省略掉Presenter;若是这个界面与数据无关,那么能够把Model也省略掉。
Presenter能够重用,因此不须要每一个Activity或者Fragment都为其分配一套MVP,能够几个Activity或者Fragment共用一个Presenter。
想要了解更多的话,请移步本人的学习笔记,若是以为有帮助的话,请点一个star✨。