注:便于更好的理解MVP并区分和MVC的差别,推荐阅读我另一篇文章Android MVC
本文MVP的框架采用谷歌官方demo方式搭建,最简化最小的一个代码形态。方便使用到自己项目开发。
概念
MVP,即Model(模型)、View(视图)、Presenter(主持人)。MVP是从经典的MVC演变而来。把数据处理,界面显示,逻辑处理分离开来。界面和数据的所有通信都是通过P层来实现。是一个将后台任务和activities/views/fragment分离的方法,让它们独立于绝大多数跟生命周期相关的事件。
MVP for Android
理解MVP:
View:与用户交互,响应用户的操作,显示数据,在Android中,通常是Activity、Fragment,View等;
Presenter:控制层,也负责处理后台任务;
Model:数据层,比如数据库接口,网络数据等;
例子:User现在要从读取一个Jack的名字并设置
MVP特点:
1、模型与视图完全分离,我们可以修改视图而不影响模型
2、可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部
3、我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁。
4、如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)
实例代码
一、View端
fragment充当View,先来看看布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/controlBackground">
<TextView
android:id="@+id/textView"
android:text="aaa"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_alignParentTop="true"/>
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
然后是fragment的java文件,代码也很少,把view的操作都写在这里,把view的操作彻底独立出来。
public class DemoFragment extends Fragment implements DemoContract.View, View.OnClickListener {
DemoContract.Presenter mPresenter;
TextView mTextView;
Button mButton;
public static DemoFragment newInstance() {
DemoFragment fragment = new DemoFragment();
return fragment;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_demo, container, false);
mTextView = (TextView)root.findViewById(R.id.textView);
mButton = (Button) root.findViewById(R.id.button);
mButton.setOnClickListener(this);
return root;
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.button:
mPresenter.demoDosomething();
break;
default:
break;
}
}
@Override
public void setName(String name) {
mTextView.setText(name);
}
@Override
public void onResume() {
super.onResume();
mPresenter.onResume();
}
@Override
public void setPresenter(DemoContract.Presenter presenter) {
mPresenter = presenter;
}
}
二、Modle数据端
这里模拟数据模拟的很简单粗暴,直接一个单例模式搞定只是为了写demo,你可以写自己的数据库,或者网络操作,或者其他
public class Data {
private static Data INSTANCE;
public static Data getInstance() {
if (INSTANCE == null) {
synchronized (Data.class) {
if (INSTANCE == null) {
INSTANCE = new Data();
}
}
}
return INSTANCE;
}
public String getName() {
return "jack";
}
}
三、Presenter
3.1、规则定义
最后我们讲讲理解难点。其实这个也比较简单
先看两个接口,这两个接口很简单,只是定义了一个标准,让大家都遵循即可,你还可以添加onDestroy等等。
BaseView.java
public interface BaseView<T> {
void setPresenter(T presenter);
}
BasePresenter.java
public interface BasePresenter {
void onResume();
void onPause();
}
这两个接口只是一个标准,demo路径下的文件才是我们开始的重点。
3.2、接口管理类DemoContract
public interface DemoContract {
interface View extends BaseView<DemoContract.Presenter> {
void setName(String name);
}
interface Presenter extends BasePresenter {
void demoDosomething();
}
}
这个类其实也很简单,它就是一个接口而已,里边放了两个新的接口View和Presenter,接口的语法很简单,继承不必重复写接口方法,由此我们可以简单的理解为:
View定义setPresenter和setName方法
Presenter定义onResume、onPause、和demoDosomething方法。
他们就是两个接口而已
1、为啥要单独写一个这个类出来呢,就是为了方便我们写不同的Contract
2、这里View里边可以把view的方法都定义一下,比如还可以添加getName,setAge,getAge等等方法
3、同理Presenter中还可以定义其它方法,这样好处是View端口可以告诉P端去做什么操作。
4、这样写我们一个看Contract类就知道我们这个MVP的代码是如何操作的。
3.3、书写DemoPresenter
接口定义好了,我们就可以写DemoPresenter来实现P端了
public class DemoPresenter implements DemoContract.Presenter {
DemoFragment mView;
public DemoPresenter(@NonNull DemoFragment view) {
mView = view;
view.setPresenter(this);
}
@Override
public void onResume() {
}
@Override
public void onPause() {
}
@Override
public void demoDosomething() {
mView.setName(Data.getInstance().getName());
}
}
一看这代码是不是好简单,继承DemoContract.Presenter,那么我实现onResume、onPause、和demoDosomething方法就行了。
这里注意构造方法DemoPresenter,拿到了fragment实例,等于P端就是这样操作了V端。
四、Activity
代码如下,很简单,总管View和Presenter的创建,作用相当于总管,创建了他们。
public class DemoActivity extends AppCompatActivity {
DemoContract.Presenter presenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
init();
}
private void init() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar ab = getSupportActionBar();
ab.setDisplayShowHomeEnabled(true);
ab.setTitle(getString(R.string.app_name));
DemoFragment fragment = (DemoFragment) getSupportFragmentManager()
.findFragmentById(R.id.container);
if (fragment == null) {
fragment = DemoFragment.newInstance();
ActivityUtils.addFragmentToActivity(getSupportFragmentManager(),
fragment, R.id.container);
}
new DemoPresenter(fragment);
}
}
总结
此例子和笔者另一文MVC for Android,例子类似。结构清晰,两篇文章都是一个对框架的一个简单理解。实际运用在项目中还需要更多的细节注意。内存泄露,nullpointerexception等等。目的主要理解MVP的作用和意义。